// GisGraphics.cpp : Defines the entry point for the DLL application.
//
//----------------------------------------------------------------------------
// CGisGraphics - Version 1.0
// Based on Anti-Grain Geometry
// Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//
//	25 Jan 2007 - Ported to AGG 2.4 Jerry Evans (jerry@novadsp.com)
//
//----------------------------------------------------------------------------

#include "GisGraphics.h"
#include <float.h>
static const double g_approxScale = 2.0;

/////class GISGRAPHICS_API Image
	CGisGraphics::Image::Image() 
	{}
	CGisGraphics::Image::~Image()
	{}

CGisGraphics::Image::Image(unsigned width, unsigned height)
{
	pmap.create(width, height, agg::org_color32,0);
	renBuf.attach(pmap.buf(),
		pmap.width(),
		pmap.height(),
	   -pmap.stride());
}
//------------------------------------------------------------------------
void CGisGraphics::Image::attach(unsigned char* buf, unsigned width, unsigned height, int stride)
{
	renBuf.attach(buf, width, height, stride);
}
//------------------------------------------------------------------------

void CGisGraphics::Image::draw(HDC h_dc, const RECT* device_rect, const RECT* bmp_rect)
{
	pmap.draw(h_dc, device_rect,bmp_rect);
}
//------------------------------------------------------------------------
bool CGisGraphics::Image::load_bitmapex(const char_t* fname)
{
	agg::pixel_map pmap_tmp;
	if(!pmap_tmp.load_from_bmp(fname)) return false;
	agg::rendering_buffer rbuf_tmp;
	rbuf_tmp.attach(pmap_tmp.buf(),
		pmap_tmp.width(),
		pmap_tmp.height(),
		-pmap_tmp.stride());
	pmap.create(pmap_tmp.width(), 
		pmap_tmp.height(), 
		agg::org_color32,
		0);
	
	renBuf.attach(pmap.buf(),
		pmap.width(),
		pmap.height(),
		-pmap.stride());
	switch(pmap_tmp.bpp())
	{
	case 16: 
		{
			agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_rgb555_to_bgra32()); 
			break;
		}
	case 24: 
		{
			agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_bgr24_to_bgra32()); 
			break;
		}
	case 32: 
		{
			agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_bgra32_to_bgra32()); 
			break;
		}
	}
	return true;
}
//----------------------------------------------------------------------------------
bool CGisGraphics::Image::load_bitmap(const char_t* fname)
{
	agg::pixel_map pmap_tmp;
	if(!pmap_tmp.load_from_bmp(fname)) return false;
	agg::rendering_buffer rbuf_tmp;
	rbuf_tmp.attach(pmap_tmp.buf(),
		pmap_tmp.width(),
		pmap_tmp.height(),
		-pmap_tmp.stride());
	pmap.create(pmap_tmp.width(), 
		pmap_tmp.height(), 
		agg::org_color32,
		0);
	
	renBuf.attach(pmap.buf(),
		pmap.width(),
		pmap.height(),
		-pmap.stride());
	switch(pmap_tmp.bpp())
	{
				case 16: 
					{
						agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_rgb555_to_bgra32()); 
						break;
					}
				case 24: 
					{
						agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_bgr24_to_bgra32()); 
						break;
					}
				case 32: 
					{
						agg::color_conv(&renBuf, &rbuf_tmp, agg::color_conv_bgra32_to_bgra32()); 
						break;
					}
	}
	return true;
}
//------------------------------------------------------------------------
int CGisGraphics::Image::width()
{ 
	return renBuf.width(); 
}
//------------------------------------------------------------------------
int CGisGraphics::Image::height()
{ 
	return renBuf.height(); 
}
//------------------------------------------------------------------------
void CGisGraphics::Image::premultiply()
{
	PixFormat pixf(renBuf);
	pixf.premultiply();
}
//------------------------------------------------------------------------
void CGisGraphics::Image::demultiply()
{
	PixFormat pixf(renBuf);
	pixf.demultiply();
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//class GISGRAPHICS_API CompoundShape
CGisGraphics::CompoundShape::~CompoundShape() 
{ }

CGisGraphics::CompoundShape::CompoundShape() :
m_path(),
m_styles()
{}

void CGisGraphics::CompoundShape::addsubstreet(int* x, int* y, int count)
{
	m_path.move_to(x[0],y[0]);
	for (int i = 1 ; i < count ; i++)
	{
		m_path.line_to(x[i],y[i]);
	}
}

void CGisGraphics::CompoundShape::addstreet(CGisGraphics::path_style &style,int* x, int* y, int count)
{
	style.path_id = m_path.start_new_path();
	m_path.move_to(x[0],y[0]);
	for (int i = 1 ; i < count ; i++)
	{
		m_path.line_to(x[i],y[i]);
	}
	
	m_styles.add(style);
}

unsigned CGisGraphics::CompoundShape::paths() const 
{ 
	return m_styles.size(); 
}

CGisGraphics::path_style* CGisGraphics::CompoundShape::style(unsigned i)
{
	return &m_styles[i];
}

void CGisGraphics::CompoundShape::rewind(unsigned path_id)
{
	m_path.rewind(path_id);			
}

unsigned CGisGraphics::CompoundShape::vertex(double* x, double* y)
{
	return m_path.vertex(x,y);
}

int CGisGraphics::CompoundShape::paths() 
{
	return m_styles.size();
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
CGisGraphics::~CGisGraphics()
{
#ifndef AGG2D_USE_FREETYPE
	::ReleaseDC(0, m_fontDC);
#endif
}

CGisGraphics::CGisGraphics() :
	m_rbuf(),
	m_pixFormat(m_rbuf),
	m_pixFormatComp(m_rbuf),
	m_pixFormatPre(m_rbuf),
	m_pixFormatCompPre(m_rbuf),
	m_renBase(m_pixFormat),
	m_renBaseComp(m_pixFormatComp),
	m_renBasePre(m_pixFormatPre),
	m_renBaseCompPre(m_pixFormatCompPre),
	m_renSolid(m_renBase),
	m_renSolidComp(m_renBaseComp),

	m_allocator(),
	m_clipBox(0,0,0,0),

	m_blendMode(BlendAlpha),
	m_imageBlendMode(BlendDst),
	m_imageBlendColor(0,0,0),

	m_scanline(),
	m_rasterizer(),

	m_masterAlpha(1.0),
	m_antiAliasGamma(1.0),

	m_fillColor(255, 255, 255),
	m_lineColor(0,   0,   0),
	m_fillGradient(),
	m_lineGradient(),

	m_lineCap(CapRound),
	m_lineJoin(JoinRound),

	m_fillGradientFlag(Solid),
	m_lineGradientFlag(Solid),
	m_fillGradientMatrix(),
	m_lineGradientMatrix(),
	m_fillGradientD1(0.0),
	m_lineGradientD1(0.0),
	m_fillGradientD2(100.0),
	m_lineGradientD2(100.0),

	m_textAngle(0.0),
	m_textAlignX(AlignLeft),
	m_textAlignY(AlignBottom),
	m_textHints(true),
	m_fontHeight(0.0),
	m_fontAscent(0.0),
	m_fontDescent(0.0),
	m_fontCacheType(RasterFontCache),

	m_imageFilter(Bilinear),
	m_imageResample(NoResample),
	m_imageFilterLut(agg::image_filter_bilinear(), true),

	m_fillGradientInterpolator(m_fillGradientMatrix),
	m_lineGradientInterpolator(m_lineGradientMatrix),

	m_linearGradientFunction(),
	m_radialGradientFunction(),

	m_lineWidth(1),
	m_evenOddFlag(false),

	m_path(),
	m_transform(),

	m_convCurve(m_path),
	m_convStroke(m_convCurve),

	m_pathTransform(m_convCurve, m_transform),
	m_strokeTransform(m_convStroke, m_transform),

	m_wrapMode(WrapRepeat),
	m_penStyle(AggPsSolid),

#ifdef AGG2D_USE_FREETYPE
	m_fontEngine(),
#else
	m_fontDC(::GetDC(0)),
	m_fontEngine(m_fontDC),
#endif
	m_fontCacheManager(m_fontEngine)
{
	lineCap(m_lineCap);
	lineJoin(m_lineJoin);
}

CGisGraphics::CGisGraphics(HDC hdc) :
	m_rbuf(),
	m_pixFormat(m_rbuf),
	m_pixFormatComp(m_rbuf),
	m_pixFormatPre(m_rbuf),
	m_pixFormatCompPre(m_rbuf),
	m_renBase(m_pixFormat),
	m_renBaseComp(m_pixFormatComp),
	m_renBasePre(m_pixFormatPre),
	m_renBaseCompPre(m_pixFormatCompPre),
	m_renSolid(m_renBase),
	m_renSolidComp(m_renBaseComp),

	m_allocator(),
	m_clipBox(0,0,0,0),

	m_blendMode(BlendAlpha),
	m_imageBlendMode(BlendDst),
	m_imageBlendColor(0,0,0),

	m_scanline(),
	m_rasterizer(),

	m_masterAlpha(1.0),
	m_antiAliasGamma(1.0),

	m_fillColor(255, 255, 255),
	m_lineColor(0,   0,   0),
	m_fillGradient(),
	m_lineGradient(),

	m_lineCap(CapRound),
	m_lineJoin(JoinRound),

	m_fillGradientFlag(Solid),
	m_lineGradientFlag(Solid),
	m_fillGradientMatrix(),
	m_lineGradientMatrix(),
	m_fillGradientD1(0.0),
	m_lineGradientD1(0.0),
	m_fillGradientD2(100.0),
	m_lineGradientD2(100.0),

	m_textAngle(0.0),
	m_textAlignX(AlignLeft),
	m_textAlignY(AlignBottom),
	m_textHints(true),
	m_fontHeight(0.0),
	m_fontAscent(0.0),
	m_fontDescent(0.0),
	m_fontCacheType(RasterFontCache),

	m_imageFilter(Bilinear),
	m_imageResample(NoResample),
	m_imageFilterLut(agg::image_filter_bilinear(), true),

	m_fillGradientInterpolator(m_fillGradientMatrix),
	m_lineGradientInterpolator(m_lineGradientMatrix),

	m_linearGradientFunction(),
	m_radialGradientFunction(),

	m_lineWidth(1),
	m_evenOddFlag(false),

	m_path(),
	m_transform(),

	m_convCurve(m_path),
	m_convStroke(m_convCurve),

	m_pathTransform(m_convCurve, m_transform),
	m_strokeTransform(m_convStroke, m_transform),

	m_wrapMode(WrapRepeat),
	m_penStyle(AggPsSolid),

#ifdef AGG2D_USE_FREETYPE
	m_fontEngine(),
#else
	m_fontDC(hdc),
	m_fontEngine(m_fontDC),
#endif
	m_fontCacheManager(m_fontEngine)
{
	lineCap(m_lineCap);
	lineJoin(m_lineJoin);
}

//------------------------------------------------------------------------
void CGisGraphics::attach(unsigned char* buf, unsigned width, unsigned height, int stride)
{
	m_rbuf.attach(buf, width, height, stride);

	m_renBase.reset_clipping(true);
	m_renBaseComp.reset_clipping(true);
	m_renBasePre.reset_clipping(true);
	m_renBaseCompPre.reset_clipping(true);


// 	m_renBase.reset_clipping(false);
//     m_renBaseComp.reset_clipping(false);
//     m_renBasePre.reset_clipping(false);
//     m_renBaseCompPre.reset_clipping(false);


	resetTransformations();
	lineWidth(1.0),
	lineColor(0,0,0);
	fillColor(255,255,255);
	textAlignment(AlignLeft, AlignBottom);
	clipBox(-50, -50, width+50, height+50);
	lineCap(CapRound);
	lineJoin(JoinRound);
	flipText(false);
	imageFilter(Bilinear);
	imageResample(NoResample);
	m_masterAlpha = 1.0;
	m_antiAliasGamma = 1.0;
	m_rasterizer.gamma(agg::gamma_none());
	m_blendMode = BlendAlpha;
}

//------------------------------------------------------------------------
void CGisGraphics::attach(Image& img)
{
	attach(img.renBuf.buf(), img.renBuf.width(), img.renBuf.height(), img.renBuf.stride());
}

//------------------------------------------------------------------------
agg::rendering_buffer* CGisGraphics::getBuf()
{
	return &m_rbuf;

}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void CGisGraphics::clipBox(double x1, double y1, double x2, double y2)
{
	m_clipBox = RectD(x1, y1, x2, y2);
	int rx1 = int(x1);
	int ry1 = int(y1);
	int rx2 = int(x2);
	int ry2 = int(y2);

	m_renBase.clip_box(rx1, ry1, rx2, ry2);
	m_renBaseComp.clip_box(rx1, ry1, rx2, ry2);
	m_renBasePre.clip_box(rx1, ry1, rx2, ry2);
	m_renBaseCompPre.clip_box(rx1, ry1, rx2, ry2);

	m_rasterizer.clip_box(x1, y1, x2, y2);
}

//------------------------------------------------------------------------
void CGisGraphics::blendMode(BlendMode m)
{
	m_blendMode = m;
	m_pixFormatComp.comp_op(m);
	m_pixFormatCompPre.comp_op(m);
}

//------------------------------------------------------------------------
CGisGraphics::BlendMode CGisGraphics::blendMode() const
{
	return m_blendMode;
}

//added by Thai Huy 2rd May 2007
//------------------------------------------------------------------------
void CGisGraphics::wrapMode(WrapMode m)
{
	m_wrapMode = m;
}

//------------------------------------------------------------------------
CGisGraphics::WrapMode CGisGraphics::wrapMode() const
{
	return m_wrapMode;
}

//------------------------------------------------------------------------
void CGisGraphics::penStyle(PenStyle ps)
{
	m_penStyle = ps;
}

//------------------------------------------------------------------------
CGisGraphics::PenStyle CGisGraphics::penStyle() const
{
	return m_penStyle;
}

//------------------------------------------------------------------------
void CGisGraphics::imageBlendMode(BlendMode m)
{
	m_imageBlendMode = m;
}

void CGisGraphics::setLinePattern(const Image& img)
{
	/*agg::rendering_buffer rbuf;
	memcpy(&rbuf, &img.renBuf, img.width() * img.height() * img.renBuf.stride())= img.renBuf;
	m_linePattern.attach(rbuf, rbuf.width(), rbuf.height(), rbuf.stride());
	*/
}

void CGisGraphics::setFillPattern(const Image& img)
{

}
//------------------------------------------------------------------------
CGisGraphics::BlendMode CGisGraphics::imageBlendMode() const
{
	return m_imageBlendMode;
}

//------------------------------------------------------------------------
void CGisGraphics::imageBlendColor(Color c)
{
	m_imageBlendColor = c;
}

//------------------------------------------------------------------------
void CGisGraphics::imageBlendColor(unsigned r, unsigned g, unsigned b, unsigned a)
{
	imageBlendColor(Color(r, g, b, a));
}

//------------------------------------------------------------------------
CGisGraphics::Color CGisGraphics::imageBlendColor() const
{
	return m_imageBlendColor;
}

//------------------------------------------------------------------------
void CGisGraphics::masterAlpha(double a)
{
	m_masterAlpha = a;
	updateRasterizerGamma();
}

//------------------------------------------------------------------------
double CGisGraphics::masterAlpha() const
{
	return m_masterAlpha;
}

//------------------------------------------------------------------------
void CGisGraphics::antiAliasGamma(double g)
{
	m_antiAliasGamma = g;
	updateRasterizerGamma();
}

//------------------------------------------------------------------------
double CGisGraphics::antiAliasGamma() const
{
	return m_antiAliasGamma;
}

//------------------------------------------------------------------------
CGisGraphics::RectD CGisGraphics::clipBox() const
{
	return m_clipBox;
}

//------------------------------------------------------------------------
void CGisGraphics::clearAll(Color c)
{
	m_renBase.clear(c);
}

//------------------------------------------------------------------------
void CGisGraphics::clearAll(unsigned r, unsigned g, unsigned b, unsigned a)
{
	clearAll(Color(r, g, b, a));
}

//------------------------------------------------------------------------
void CGisGraphics::clearClipBox(Color c)
{
	m_renBase.copy_bar(0, 0, m_renBase.width(), m_renBase.height(), c);
}

//------------------------------------------------------------------------
void CGisGraphics::clearClipBox(unsigned r, unsigned g, unsigned b, unsigned a)
{
	clearClipBox(Color(r, g, b, a));
}

//------------------------------------------------------------------------
void CGisGraphics::worldToScreen(double& x, double& y) const
{
	m_transform.transform(&x, &y);
}

//------------------------------------------------------------------------
void CGisGraphics::screenToWorld(double& x, double& y) const
{
	m_transform.inverse_transform(&x, &y);
}

//------------------------------------------------------------------------
double CGisGraphics::worldToScreen(double scalar) const
{
	double x1 = 0;
	double y1 = 0;
	double x2 = scalar;
	double y2 = scalar;
	worldToScreen(x1, y1);
	worldToScreen(x2, y2);
	return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068;
}

//------------------------------------------------------------------------
double CGisGraphics::screenToWorld(double scalar) const
{
	double x1 = 0;
	double y1 = 0;
	double x2 = scalar;
	double y2 = scalar;
	screenToWorld(x1, y1);
	screenToWorld(x2, y2);
	return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) * 0.7071068;
}

//------------------------------------------------------------------------
void CGisGraphics::alignPoint(double& x, double& y) const
{
	worldToScreen(x, y);
	x = floor(x) + 0.5;
	y = floor(y) + 0.5;
	screenToWorld(x, y);
}

//------------------------------------------------------------------------
bool CGisGraphics::inBox(double worldX, double worldY) const
{
	worldToScreen(worldX, worldY);
	return m_renBase.inbox(int(worldX), int(worldY));
}


//------------------------------------------------------------------------
CGisGraphics::Transformations CGisGraphics::transformations() const
{
	Transformations tr;
	m_transform.store_to(tr.affineMatrix);
	return tr;
}

//------------------------------------------------------------------------
void CGisGraphics::transformations(const Transformations& tr)
{
	m_transform.load_from(tr.affineMatrix);
	m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
	m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
}

//------------------------------------------------------------------------
void CGisGraphics::resetTransformations()
{
	m_transform.reset();
}

//------------------------------------------------------------------------
void CGisGraphics::rotate(double angle)          { m_transform *= agg::trans_affine_rotation(angle);   }
void CGisGraphics::skew(double sx, double sy)    { m_transform *= agg::trans_affine_skewing(sx, sy);   }
void CGisGraphics::translate(double x, double y) { m_transform *= agg::trans_affine_translation(x, y); }

//------------------------------------------------------------------------
void CGisGraphics::affine(const Affine& tr)
{
	m_transform *= tr;
	m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
	m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
}

//------------------------------------------------------------------------
void CGisGraphics::affine(const Transformations& tr)
{
	affine(agg::trans_affine(tr.affineMatrix[0], tr.affineMatrix[1], tr.affineMatrix[2],
							 tr.affineMatrix[3], tr.affineMatrix[4], tr.affineMatrix[5]));
}

//------------------------------------------------------------------------
void CGisGraphics::scale(double sx, double sy)
{
	m_transform *= agg::trans_affine_scaling(sx, sy);
	m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
	m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
}

//------------------------------------------------------------------------
void CGisGraphics::parallelogram(double x1, double y1, double x2, double y2, const double* para)
{
	m_transform *= agg::trans_affine(x1, y1, x2, y2, para);
	m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
	m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
}

//------------------------------------------------------------------------
void CGisGraphics::viewport(double worldX1, double worldY1, double worldX2, double worldY2,
					 double screenX1, double screenY1, double screenX2, double screenY2,
					 ViewportOption opt)
{
	agg::trans_viewport vp;
	switch(opt)
	{
		case Anisotropic: vp.preserve_aspect_ratio(0.0, 0.0, agg::aspect_ratio_stretch); break;
		case XMinYMin:    vp.preserve_aspect_ratio(0.0, 0.0, agg::aspect_ratio_meet);    break;
		case XMidYMin:    vp.preserve_aspect_ratio(0.5, 0.0, agg::aspect_ratio_meet);    break;
		case XMaxYMin:    vp.preserve_aspect_ratio(1.0, 0.0, agg::aspect_ratio_meet);    break;
		case XMinYMid:    vp.preserve_aspect_ratio(0.0, 0.5, agg::aspect_ratio_meet);    break;
		case XMidYMid:    vp.preserve_aspect_ratio(0.5, 0.5, agg::aspect_ratio_meet);    break;
		case XMaxYMid:    vp.preserve_aspect_ratio(1.0, 0.5, agg::aspect_ratio_meet);    break;
		case XMinYMax:    vp.preserve_aspect_ratio(0.0, 1.0, agg::aspect_ratio_meet);    break;
		case XMidYMax:    vp.preserve_aspect_ratio(0.5, 1.0, agg::aspect_ratio_meet);    break;
		case XMaxYMax:    vp.preserve_aspect_ratio(1.0, 1.0, agg::aspect_ratio_meet);    break;
	}
	vp.world_viewport(worldX1,   worldY1,  worldX2,  worldY2);
	vp.device_viewport(screenX1, screenY1, screenX2, screenY2);
	m_transform *= vp.to_affine();
	m_convCurve.approximation_scale(worldToScreen(1.0) * g_approxScale);
	m_convStroke.approximation_scale(worldToScreen(1.0) * g_approxScale);
}

//------------------------------------------------------------------------
void CGisGraphics::fillColor(Color c)
{
	m_fillColor = c;
	m_fillGradientFlag = Solid;
}

//------------------------------------------------------------------------
void CGisGraphics::fillColor(unsigned r, unsigned g, unsigned b, unsigned a)
{
	fillColor(Color(r, g, b, a));
}

//------------------------------------------------------------------------
void CGisGraphics::noFill()
{
	fillColor(Color(0, 0, 0, 0));
}

//------------------------------------------------------------------------
void CGisGraphics::lineColor(Color c)
{
	m_lineColor = c;
	m_lineGradientFlag = Solid;
}

//------------------------------------------------------------------------
void CGisGraphics::lineColor(unsigned r, unsigned g, unsigned b, unsigned a)
{
	lineColor(Color(r, g, b, a));
}

//------------------------------------------------------------------------
void CGisGraphics::noLine()
{
	lineColor(Color(0, 0, 0, 0));
}

//------------------------------------------------------------------------
CGisGraphics::Color CGisGraphics::fillColor() const
{
	return m_fillColor;
}

//------------------------------------------------------------------------
CGisGraphics::Color CGisGraphics::lineColor() const
{
	return m_lineColor;
}

//------------------------------------------------------------------------
void CGisGraphics::fillLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, double profile)
{
	int i;
	int startGradient = 128 - int(profile * 127.0);
	int endGradient   = 128 + int(profile * 127.0);
	if (endGradient <= startGradient) endGradient = startGradient + 1;
	double k = 1.0 / double(endGradient - startGradient);
	for (i = 0; i < startGradient; i++)
	{
		m_fillGradient[i] = c1;
	}
	for (; i < endGradient; i++)
	{
		m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
	}
	for (; i < 256; i++)
	{
		m_fillGradient[i] = c2;
	}
	double angle = atan2(y2-y1, x2-x1);
	m_fillGradientMatrix.reset();
	m_fillGradientMatrix *= agg::trans_affine_rotation(angle);
	m_fillGradientMatrix *= agg::trans_affine_translation(x1, y1);
	m_fillGradientMatrix *= m_transform;
	m_fillGradientMatrix.invert();
	m_fillGradientD1 = 0.0;
	m_fillGradientD2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
	m_fillGradientFlag = Linear;
	m_fillColor = Color(0,0,0);  // Set some real color
}

//------------------------------------------------------------------------
void CGisGraphics::lineLinearGradient(double x1, double y1, double x2, double y2, Color c1, Color c2, double profile)
{
	int i;
	int startGradient = 128 - int(profile * 128.0);
	int endGradient   = 128 + int(profile * 128.0);
	if (endGradient <= startGradient) endGradient = startGradient + 1;
	double k = 1.0 / double(endGradient - startGradient);
	for (i = 0; i < startGradient; i++)
	{
		m_lineGradient[i] = c1;
	}
	for (; i < endGradient; i++)
	{
		m_lineGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
	}
	for (; i < 256; i++)
	{
		m_lineGradient[i] = c2;
	}
	double angle = atan2(y2-y1, x2-x1);
	m_lineGradientMatrix.reset();
	m_lineGradientMatrix *= agg::trans_affine_rotation(angle);
	m_lineGradientMatrix *= agg::trans_affine_translation(x1, y1);
	m_fillGradientMatrix *= m_transform;
	m_lineGradientMatrix.invert();
	m_lineGradientD1 = 0;
	m_lineGradientD2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
	m_lineGradientFlag = Linear;
	m_lineColor = Color(0,0,0);  // Set some real color
}

//------------------------------------------------------------------------
void CGisGraphics::fillRadialGradient(double x, double y, double r, Color c1, Color c2, double profile)
{
	int i;
	int startGradient = 128 - int(profile * 127.0);
	int endGradient   = 128 + int(profile * 127.0);
	if (endGradient <= startGradient) endGradient = startGradient + 1;
	double k = 1.0 / double(endGradient - startGradient);
	for (i = 0; i < startGradient; i++)
	{
		m_fillGradient[i] = c1;
	}
	for (; i < endGradient; i++)
	{
		m_fillGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
	}
	for (; i < 256; i++)
	{
		m_fillGradient[i] = c2;
	}
	m_fillGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_fillGradientMatrix.reset();
	m_fillGradientMatrix *= agg::trans_affine_translation(x, y);
	m_fillGradientMatrix.invert();
	m_fillGradientD1 = 0;
	m_fillGradientFlag = Radial;
	m_fillColor = Color(0,0,0);  // Set some real color
}

//------------------------------------------------------------------------
void CGisGraphics::lineRadialGradient(double x, double y, double r, Color c1, Color c2, double profile)
{
	int i;
	int startGradient = 128 - int(profile * 128.0);
	int endGradient   = 128 + int(profile * 128.0);
	if (endGradient <= startGradient) endGradient = startGradient + 1;
	double k = 1.0 / double(endGradient - startGradient);
	for (i = 0; i < startGradient; i++)
	{
		m_lineGradient[i] = c1;
	}
	for (; i < endGradient; i++)
	{
		m_lineGradient[i] = c1.gradient(c2, double(i - startGradient) * k);
	}
	for (; i < 256; i++)
	{
		m_lineGradient[i] = c2;
	}
	m_lineGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_lineGradientMatrix.reset();
	m_lineGradientMatrix *= agg::trans_affine_translation(x, y);
	m_lineGradientMatrix.invert();
	m_lineGradientD1 = 0;
	m_lineGradientFlag = Radial;
	m_lineColor = Color(0,0,0);  // Set some real color
}

//------------------------------------------------------------------------
void CGisGraphics::fillRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3)
{
	int i;
	for (i = 0; i < 128; i++)
	{
		m_fillGradient[i] = c1.gradient(c2, double(i) / 127.0);
	}
	for (; i < 256; i++)
	{
		m_fillGradient[i] = c2.gradient(c3, double(i - 128) / 127.0);
	}
	m_fillGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_fillGradientMatrix.reset();
	m_fillGradientMatrix *= agg::trans_affine_translation(x, y);
	m_fillGradientMatrix.invert();
	m_fillGradientD1 = 0;
	m_fillGradientFlag = Radial;
	m_fillColor = Color(0,0,0);  // Set some real color
}

//------------------------------------------------------------------------
void CGisGraphics::lineRadialGradient(double x, double y, double r, Color c1, Color c2, Color c3)
{
	int i;
	for (i = 0; i < 128; i++)
	{
		m_lineGradient[i] = c1.gradient(c2, double(i) / 127.0);
	}
	for (; i < 256; i++)
	{
		m_lineGradient[i] = c2.gradient(c3, double(i - 128) / 127.0);
	}
	m_lineGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_lineGradientMatrix.reset();
	m_lineGradientMatrix *= agg::trans_affine_translation(x, y);
	m_lineGradientMatrix.invert();
	m_lineGradientD1 = 0;
	m_lineGradientFlag = Radial;
	m_lineColor = Color(0,0,0);  // Set some real color
}

void CGisGraphics::fillRadialGradient(double x, double y, double r)
{
	m_fillGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_fillGradientMatrix.reset();
	m_fillGradientMatrix *= agg::trans_affine_translation(x, y);
	m_fillGradientMatrix.invert();
	m_fillGradientD1 = 0;
}

//------------------------------------------------------------------------
void CGisGraphics::lineRadialGradient(double x, double y, double r)
{
	m_lineGradientD2 = worldToScreen(r);
	worldToScreen(x, y);
	m_lineGradientMatrix.reset();
	m_lineGradientMatrix *= agg::trans_affine_translation(x, y);
	m_lineGradientMatrix.invert();
	m_lineGradientD1 = 0;
}

//------------------------------------------------------------------------
void CGisGraphics::lineWidth(double w)
{
	m_lineWidth = w;
	m_convStroke.width(w);
}

//------------------------------------------------------------------------
double CGisGraphics::lineWidth(double w) const
{
	return m_lineWidth;
}

//------------------------------------------------------------------------
void CGisGraphics::fillEvenOdd(bool evenOddFlag)
{
	m_evenOddFlag = evenOddFlag;
	m_rasterizer.filling_rule(evenOddFlag ? agg::fill_even_odd : agg::fill_non_zero);
}

//------------------------------------------------------------------------
bool CGisGraphics::fillEvenOdd() const
{
	return m_evenOddFlag;
}

//------------------------------------------------------------------------
void CGisGraphics::lineCap(LineCap cap)
{
	m_lineCap = cap;
	m_convStroke.line_cap((agg::line_cap_e)cap);
}

//------------------------------------------------------------------------
CGisGraphics::LineCap CGisGraphics::lineCap() const
{
	return m_lineCap;
}

//------------------------------------------------------------------------
void CGisGraphics::lineJoin(LineJoin join)
{
	m_lineJoin = join;
	m_convStroke.line_join((agg::line_join_e)join);
}

//------------------------------------------------------------------------
CGisGraphics::LineJoin CGisGraphics::lineJoin() const
{
	return m_lineJoin;
}

//------------------------------------------------------------------------
void CGisGraphics::addLine(double x1, double y1, double x2, double y2)
{
	m_path.move_to(x1, y1);
	m_path.line_to(x2, y2);
}

//------------------------------------------------------------------------
void CGisGraphics::line(double x1, double y1, double x2, double y2)
{
	m_path.remove_all();
	addLine(x1, y1, x2, y2);
	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::triangle(double x1, double y1, double x2, double y2, double x3, double y3)
{
	m_path.remove_all();
	m_path.move_to(x1, y1);
	m_path.line_to(x2, y2);
	m_path.line_to(x3, y3);
	m_path.close_polygon();
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::rectangle(double x1, double y1, double x2, double y2)
{
	m_path.remove_all();
	m_path.move_to(x1, y1);
	m_path.line_to(x2, y1);
	m_path.line_to(x2, y2);
	m_path.line_to(x1, y2);
	m_path.close_polygon();
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::rectangle2(double x1, double y1, double x2, double y2)
{
    m_path.remove_all();
    m_path.move_to(x1, y1);
    m_path.line_to(x2, y1);
    m_path.line_to(x2, y2);
    m_path.line_to(x1, y2);
    m_path.close_polygon();
    drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::roundedRect(double x1, double y1, double x2, double y2, double r)
{
	m_path.remove_all();
	agg::rounded_rect rc(x1, y1, x2, y2, r);
	rc.normalize_radius();
	rc.approximation_scale(worldToScreen(1.0) * g_approxScale);
	// JME audit
	//m_path.add_path(rc, 0, false);
	m_path.concat_path(rc,0);
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::roundedRect(double x1, double y1, double x2, double y2, double rx, double ry)
{
	m_path.remove_all();
	agg::rounded_rect rc;
	rc.rect(x1, y1, x2, y2);
	rc.radius(rx, ry);
	rc.normalize_radius();
	//m_path.add_path(rc, 0, false);
	m_path.concat_path(rc,0); // JME
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::roundedRect(double x1, double y1, double x2, double y2,
						double rx_bottom, double ry_bottom,
						double rx_top,    double ry_top)
{
	m_path.remove_all();
	agg::rounded_rect rc;
	rc.rect(x1, y1, x2, y2);
	rc.radius(rx_bottom, ry_bottom, rx_top, ry_top);
	rc.normalize_radius();
	rc.approximation_scale(worldToScreen(1.0) * g_approxScale);
	//m_path.add_path(rc, 0, false);
	m_path.concat_path(rc,0); // JME
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::ellipse(double cx, double cy, double rx, double ry)
{
	m_path.remove_all();
	agg::bezier_arc arc(cx, cy, rx, ry, 0, 2*pi());
	//m_path.add_path(arc, 0, false);
	m_path.concat_path(arc,0); // JME
	m_path.close_polygon();
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::arc(double cx, double cy, double rx, double ry, double start, double sweep)
{
	m_path.remove_all();
	agg::bezier_arc arc(cx, cy, rx, ry, start, sweep);
	//m_path.add_path(arc, 0, false);
	m_path.concat_path(arc,0); // JME
	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::star(double cx, double cy, double r1, double r2, double startAngle, int numRays)
{
	m_path.remove_all();
	double da = agg::pi / double(numRays);
	double a = startAngle;
	int i;
	for (i = 0; i < numRays; i++)
	{
		double x = cos(a) * r2 + cx;
		double y = sin(a) * r2 + cy;
		if (i) m_path.line_to(x, y);
		else   m_path.move_to(x, y);
		a += da;
		m_path.line_to(cos(a) * r1 + cx, sin(a) * r1 + cy);
		a += da;
	}
	closePolygon();
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::curve(double x1, double y1, double x2, double y2, double x3, double y3)
{
	m_path.remove_all();
	m_path.move_to(x1, y1);
	m_path.curve3(x2, y2, x3, y3);
	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::curve(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
	m_path.remove_all();
	m_path.move_to(x1, y1);
	m_path.curve4(x2, y2, x3, y3, x4, y4);
	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::polygon(double* xy, int numPoints)
{
	m_path.remove_all();
	//m_path.add_poly(xy, numPoints);
	m_path.concat_poly(xy,numPoints,true); // JME
	closePolygon();
	drawPath(FillAndStroke);
}

//------------------------------------------------------------------------
void CGisGraphics::polyline(double* xy, int numPoints)
{
	m_path.remove_all();
	//m_path.add_poly(xy, numPoints);
	m_path.concat_poly(xy,numPoints,true); // JME
	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::polycurve4(double* anchorxy, double* ctrlxy, int numAnchorPoints)
{
	m_path.remove_all();
	
	int i = 0;
	m_path.move_to(anchorxy[0], anchorxy[1]); // pAnchor[0].x, pAnchor[0].y);
	m_path.curve4(ctrlxy[i*2 + 1], ctrlxy[(i*2 + 1) + 1], ctrlxy[(i + 1)*2], ctrlxy[(i+1)*2 + 1], 
					anchorxy[i + 1], anchorxy[(i + 1) + 1]);

	for (i = 1 ;i < numAnchorPoints - 1 ; i++)
	{
		m_path.curve4(ctrlxy[i*2 + 1], ctrlxy[(i*2 + 1) + 1], ctrlxy[(i + 1)*2], ctrlxy[(i+1)*2 + 1], 
					anchorxy[i + 1], anchorxy[(i + 1) + 1]);
	}

	drawPath(StrokeOnly);
}

//------------------------------------------------------------------------
void CGisGraphics::flipText(bool flip)
{
	m_fontEngine.flip_y(flip);
}

//test
void CGisGraphics::font(const char_t* fontName,  
						double height, FontCacheType ch,
						bool bold,bool italic,
						double angle)
{
	m_textAngle = angle;
	m_fontHeight = height;
	m_fontCacheType = ch;
	
#ifdef AGG2D_USE_FREETYPE
	m_fontEngine.load_font(fontName,
		0,
		(ch == VectorFontCache) ?
		agg::glyph_ren_outline :
	agg::glyph_ren_agg_gray8);
	m_fontEngine.hinting(m_textHints);
	m_fontEngine.height((ch == VectorFontCache) ? height : worldToScreen(height));
#else
	m_fontEngine.hinting(m_textHints);
	m_fontEngine.italic(italic);
	m_fontEngine.height(height);
	m_fontEngine.weight(bold ? 700 : 200);
	m_fontEngine.create_font(fontName, agg::glyph_ren_outline);
	
	//m_fontEngine.create_font(fontName,
	//                       (ch == VectorFontCache) ?
	//                         agg::glyph_ren_outline :
	//                        agg::glyph_ren_agg_gray8,
	//                     (ch == VectorFontCache) ? height : worldToScreen(height),
	//                     0.0,
	//                     bold ? 700 : 400,
	//                     italic);
	
#endif
}
//////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------
/*
void CGisGraphics::font(const char* fontName,
				 double height, FontCacheType ch,
				 bool bold,
				 bool italic,
				 double angle)
{
	m_textAngle = angle;
	m_fontHeight = height;
	m_fontCacheType = ch;

#ifdef AGG2D_USE_FREETYPE
	m_fontEngine.load_font(fontName,
						   0,
						   (ch == VectorFontCache) ?
								agg::glyph_ren_outline :
								agg::glyph_ren_agg_gray8);
	m_fontEngine.hinting(m_textHints);
	m_fontEngine.height((ch == VectorFontCache) ? height : worldToScreen(height));
#else
	m_fontEngine.hinting(m_textHints);
	m_fontEngine.italic(italic);
	m_fontEngine.height(height);
	m_fontEngine.weight(bold ? 700 : 200);
	m_fontEngine.create_font(fontName, agg::glyph_ren_outline);

	  //m_fontEngine.create_font(fontName,
	  //                       (ch == VectorFontCache) ?
	  //                         agg::glyph_ren_outline :
	  //                        agg::glyph_ren_agg_gray8,
	  //                     (ch == VectorFontCache) ? height : worldToScreen(height),
	  //                     0.0,
	  //                     bold ? 700 : 400,
	  //                     italic);

#endif
}
*/
//------------------------------------------------------------------------
double CGisGraphics::fontHeight() const
{
   return m_fontHeight;
}

//------------------------------------------------------------------------
void CGisGraphics::textAlignment(TextAlignment alignX, TextAlignment alignY)
{
   m_textAlignX = alignX;
   m_textAlignY = alignY;
}

//------------------------------------------------------------------------
double CGisGraphics::textWidth(const char* str)
{
	double x = 0;
	double y = 0;
	bool first = true;
	while(*str)
	{
		const agg::glyph_cache* glyph = m_fontCacheManager.glyph(*str);
		if(glyph)
		{
			if(!first) m_fontCacheManager.add_kerning(&x, &y);
			x += glyph->advance_x;
			y += glyph->advance_y;
			first = true;
		}
		++str;
	}
	return (m_fontCacheType == VectorFontCache) ? x : screenToWorld(x);
}

double CGisGraphics::textWidth(const unsigned short* str)
{
	double x = 0;
	double y = 0;
	bool first = true;
	while(*str)
	{
		const agg::glyph_cache* glyph = m_fontCacheManager.glyph(*str);
		if(glyph)
		{
			if(!first) m_fontCacheManager.add_kerning(&x, &y);
			x += glyph->advance_x;
			y += glyph->advance_y;
			first = true;
		}
		++str;
	}
	return (m_fontCacheType == VectorFontCache) ? x : screenToWorld(x);
}

//------------------------------------------------------------------------
bool CGisGraphics::textHints() const
{
   return m_textHints;
}

//------------------------------------------------------------------------
void CGisGraphics::textHints(bool hints)
{
   m_textHints = hints;
}

//------------------------------------------------------------------------
void CGisGraphics::text(double x, double y, const char* str, bool roundOff, double ddx, double ddy)
{
   double dx = 0.0;
   double dy = 0.0;

   switch(m_textAlignX)
   {
	   case AlignCenter:  dx = -textWidth(str) * 0.5; break;
	   case AlignRight:   dx = -textWidth(str);       break;
	   default: break;
   }


   double asc = fontHeight();
   const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
   if(glyph)
   {
	   asc = glyph->bounds.y2 - glyph->bounds.y1;
   }

   if(m_fontCacheType == RasterFontCache)
   {
	   asc = screenToWorld(asc);
   }

   switch(m_textAlignY)
   {
	   case AlignCenter:  dy = -asc * 0.5; break;
	   case AlignTop:     dy = -asc;       break;
	   default: break;
   }

   if(m_fontEngine.flip_y()) dy = -dy;

   agg::trans_affine  mtx;

	double start_x = x + dx;
	double start_y = y + dy;

	if (roundOff)
	{
		start_x = int(start_x);
		start_y = int(start_y);
	}
	start_x += ddx;
	start_y += ddy;

	mtx *= agg::trans_affine_translation(-x, -y);
	mtx *= agg::trans_affine_rotation(m_textAngle);
	mtx *= agg::trans_affine_translation(x, y);

	agg::conv_transform<FontCacheManager::path_adaptor_type> tr(m_fontCacheManager.path_adaptor(), mtx);

	if(m_fontCacheType == RasterFontCache)
	{
		worldToScreen(start_x, start_y);
	}

	int i;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(i) m_fontCacheManager.add_kerning(&x, &y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);

			if(glyph->data_type == agg::glyph_data_outline)
			{
				m_path.remove_all();
				//m_path.add_path(tr, 0, false);
				m_path.concat_path(tr,0); // JME
				drawPath();
			}

			if(glyph->data_type == agg::glyph_data_gray8)
			{
				render(m_fontCacheManager.gray8_adaptor(),
					   m_fontCacheManager.gray8_scanline());
			}
			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
}

//------------------------------------------------------------------------
void CGisGraphics::textPath(double x, double y, const char* str, bool bCurve, double nInterpolation)
{
	if(pathLength() <= 0)
		return ;

	double dx = 0.0;
   double dy = 0.0;
   agg::path_storage	tmpPath;
   tmpPath = m_path;
   switch(m_textAlignX)
   {
	   case AlignCenter:  dx = -textWidth(str) * 0.5; break;
	   case AlignRight:   dx = -textWidth(str);       break;
	   default: break;
   }


   double asc = fontHeight();
   const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
   if(glyph)
   {
	   asc = glyph->bounds.y2 - glyph->bounds.y1;
   }

   if(m_fontCacheType == RasterFontCache)
   {
	   asc = screenToWorld(asc);
   }

   switch(m_textAlignY)
   {
	   case AlignCenter:  dy = -asc * 0.5; break;
	   case AlignTop:     dy = -asc;       break;
	   default: break;
   }

   if(m_fontEngine.flip_y()) dy = -dy;

	double start_x = x + dx;
	double start_y = y + dy;

	typedef agg::conv_bspline<PathTransform> conv_bspline_trans_type;
	typedef agg::conv_bspline<agg::path_storage> conv_bspline_type;
	//conv_bspline_type bspline(m_path);
	conv_bspline_trans_type bspline(m_pathTransform);

	bspline.interpolation_step(nInterpolation);

	agg::trans_single_path SinglePath;
	if(bCurve)
		SinglePath.add_path(bspline);
	else
		SinglePath.add_path(m_pathTransform);

	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>				conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>							conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path>	conv_font_trans_type;

	conv_font_curve_type		Curve(m_fontCacheManager.path_adaptor());
	conv_font_segm_type			Segment(Curve);

	if(m_fontCacheType == RasterFontCache)
	{
		worldToScreen(start_x, start_y);
	}

	int i;
	
	agg::path_storage tmpPs = m_path;
	tmpPs.rewind(0);
	int numpoints = 0;
	int nvertices = tmpPs.total_vertices();
	double *px = new double[nvertices];
	double *py = new double[nvertices];
	while (tmpPs.vertex(&dx, &dy) != agg::path_cmd_stop)
	{
		px[numpoints] = dx;
		py[numpoints] = dy;
		numpoints++;
	}
	int ncurnode = 0;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(start_x > SinglePath.total_length()) break;
			double tx = start_x;
			double ty = start_y;
			SinglePath.transform(&tx, &ty);
			double d = start_x;
			int jn = 0;
			double D = agg::calc_distance(px[0], py[0], px[1], py[1]);
			while( D < d + 1.0  && jn < nvertices - 1 && nvertices > 2)
			{
				jn++;
				D += agg::calc_distance(px[jn], py[jn], px[jn+1], py[jn+1]);
			}
			ncurnode = jn;
			double dbRot;
			dbRot = atan2(py[ncurnode + 1] - py[ncurnode], px[ncurnode + 1] - px[ncurnode]);

			m_fontCacheManager.add_kerning(&start_x, &start_y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);

			if(glyph->data_type == agg::glyph_data_outline)
			{
				agg::trans_affine mtx;
				mtx *= agg::trans_affine_translation(-start_x, -start_y);
				mtx *= agg::trans_affine_rotation(dbRot);
				mtx *= agg::trans_affine_translation(tx, ty);
				agg::path_storage glyphps;
				glyphps.concat_path(Curve);
				agg::conv_transform<agg::path_storage> Trans(glyphps,mtx);
				m_path.remove_all();
				m_path.concat_path(Trans, 0);
				drawPath();
			}

			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	m_path = tmpPath;
	delete []px;
	delete []py;
}

void CGisGraphics::nextTextLine(double dbSpace)
{
	m_path.rewind(0);
	double px1, py1, px2, py2;
	m_path.vertex(0, &px1, &py1);
	m_path.vertex(m_path.total_vertices()-1, &px2, &py2);
	double xxx, yyy;
	agg::calc_orthogonal(-dbSpace, px1, py1, px2, py2, &xxx, &yyy);
	resetPath();
	moveTo(px1+xxx, py1+yyy);
	lineTo(px2+xxx, py2+yyy);
}

void CGisGraphics::lastVertex(double *x, double *y)
{
	m_path.last_vertex(x, y);
}
//editted by Thai Huy on 19th May 2007
//---------------------------------------------------------------------------------
void CGisGraphics::textPathEx(double x, double y, const unsigned short* str, bool bCurve, double nInterpolation)
{
	if(pathLength() <= 0)
		return ;

   double dx = 0.0;
   double dy = 0.0;
   agg::path_storage	tmpPath;
   tmpPath = m_path;

   double asc = fontHeight();
   const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
   if(glyph)
   {
	   asc = glyph->bounds.y2 - glyph->bounds.y1;
   }

   if(m_fontCacheType == RasterFontCache)
   {
	   asc = screenToWorld(asc);
   }

   switch(m_textAlignY)
   {
	   case AlignCenter:  dy = -asc * 0.5; break;
	   case AlignTop:     dy = -asc;       break;
	   default: break;
   }

   if(m_fontEngine.flip_y()) dy = -dy;

	double start_x = x + dx;
	double start_y = y + dy;

	typedef agg::conv_bspline<PathTransform> conv_bspline_trans_type;
	typedef agg::conv_bspline<agg::path_storage> conv_bspline_type;
	//conv_bspline_type bspline(m_path);
	conv_bspline_trans_type bspline(m_pathTransform);

	bspline.interpolation_step(nInterpolation);

	agg::trans_single_path SinglePath;
	if(bCurve)
		SinglePath.add_path(bspline);
	else
		SinglePath.add_path(m_pathTransform);

	SinglePath.preserve_x_scale(true);
	
	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>				conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>							conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path>	conv_font_trans_type;

	conv_font_curve_type		Curve(m_fontCacheManager.path_adaptor());
	conv_font_segm_type			Segment(Curve);

	if(m_fontCacheType == RasterFontCache)
	{
		worldToScreen(start_x, start_y);
	}

	int i;

	agg::path_storage tmpPs = m_path;
	agg::path_storage psFont;
	m_path.remove_all();
	tmpPs.rewind(0);
	int numpoints = 0;
	int nvertices = tmpPs.total_vertices();
	double *px = new double[nvertices];
	double *py = new double[nvertices];
	while (tmpPs.vertex(&dx, &dy) != agg::path_cmd_stop)
	{
		px[numpoints] = dx;
		py[numpoints] = dy;
		numpoints++;
	}
	int ncurnode = 0;

	for (i = 0; str[i] && str[i] < 7930; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(start_x > SinglePath.total_length()) break;
			double tx = start_x;
			double ty = start_y;
			SinglePath.transform(&tx, &ty);
			double d = start_x;
			int jn = 0;
			double D = agg::calc_distance(px[0], py[0], px[1], py[1]);
			while( D < d + 1.0  && jn < nvertices - 1 && nvertices > 2)
			{
				jn++;
				D += agg::calc_distance(px[jn], py[jn], px[jn+1], py[jn+1]);
			}
			ncurnode = jn;
			double dbRot;
			dbRot = atan2(py[ncurnode + 1] - py[ncurnode], px[ncurnode + 1] - px[ncurnode]);

			m_fontCacheManager.add_kerning(&start_x, &start_y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);

			if(glyph->data_type == agg::glyph_data_outline)
			{
				agg::trans_affine mtx;
				mtx *= agg::trans_affine_translation(-start_x, -start_y);
				mtx *= agg::trans_affine_rotation(dbRot);
				mtx *= agg::trans_affine_translation(tx, ty);
				agg::path_storage glyphps;
				glyphps.concat_path(Curve);
				agg::conv_transform<agg::path_storage> Trans(glyphps,mtx);
				//m_path.remove_all();
				//m_path.concat_path(Trans, 0);
				//drawPath();
				psFont.concat_path(Trans, 0);
			}

			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	addPath(psFont);
	drawPath();
	//restore path storage
	m_path = tmpPath;
	delete []px;
	delete []py;
}

void CGisGraphics::textPathLineEx(int nLine, double x, double y, const unsigned short* str, bool bCurve, double nInterpolation)
{
	if(pathLength() <= 0)
		return ;

   double dx = 0.0;
   double dy = 0.0;
   agg::path_storage	tmpPath;
   tmpPath = m_path;
	if(nLine > 0)
	{
		m_path.rewind(0);
		double px1, py1, px2, py2;
		m_path.vertex(0, &px1, &py1);
		m_path.vertex(m_path.total_vertices()-1, &px2, &py2);
		double xxx, yyy;
		double dbSpace = nLine * (m_fontHeight + 2);
		agg::calc_orthogonal(-dbSpace, px1, py1, px2, py2, &xxx, &yyy);
		resetPath();
		moveTo(px1+xxx, py1+yyy);
		lineTo(px2+xxx, py2+yyy);
	}
	
   double asc = fontHeight();
   const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
   if(glyph)
   {
	   asc = glyph->bounds.y2 - glyph->bounds.y1;
   }

   if(m_fontCacheType == RasterFontCache)
   {
	   asc = screenToWorld(asc);
   }

   switch(m_textAlignY)
   {
	   case AlignCenter:  dy = -asc * 0.5; break;
	   case AlignTop:     dy = -asc;       break;
	   default: break;
   }

   if(m_fontEngine.flip_y()) dy = -dy;

	double start_x = x + dx;
	double start_y = y + dy;

	typedef agg::conv_bspline<PathTransform> conv_bspline_trans_type;
	typedef agg::conv_bspline<agg::path_storage> conv_bspline_type;
	//conv_bspline_type bspline(m_path);
	conv_bspline_trans_type bspline(m_pathTransform);

	bspline.interpolation_step(nInterpolation);

	agg::trans_single_path SinglePath;
	if(bCurve)
		SinglePath.add_path(bspline);
	else
		SinglePath.add_path(m_pathTransform);

	SinglePath.preserve_x_scale(true);
	
	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>				conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>							conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path>	conv_font_trans_type;

	conv_font_curve_type		Curve(m_fontCacheManager.path_adaptor());
	conv_font_segm_type			Segment(Curve);

	if(m_fontCacheType == RasterFontCache)
	{
		worldToScreen(start_x, start_y);
	}

	int i;

	agg::path_storage tmpPs = m_path;
	agg::path_storage psFont;
	m_path.remove_all();
	tmpPs.rewind(0);
	int numpoints = 0;
	int nvertices = tmpPs.total_vertices();
	double *px = new double[nvertices];
	double *py = new double[nvertices];
	while (tmpPs.vertex(&dx, &dy) != agg::path_cmd_stop)
	{
		px[numpoints] = dx;
		py[numpoints] = dy;
		numpoints++;
	}
	int ncurnode = 0;

	for (i = 0; str[i] && str[i] < 7930; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(start_x > SinglePath.total_length()) break;
			double tx = start_x;
			double ty = start_y;
			SinglePath.transform(&tx, &ty);
			double d = start_x;
			int jn = 0;
			double D = agg::calc_distance(px[0], py[0], px[1], py[1]);
			while( D < d + 1.0  && jn < nvertices - 1 && nvertices > 2)
			{
				jn++;
				D += agg::calc_distance(px[jn], py[jn], px[jn+1], py[jn+1]);
			}
			ncurnode = jn;
			double dbRot;
			dbRot = atan2(py[ncurnode + 1] - py[ncurnode], px[ncurnode + 1] - px[ncurnode]);

			m_fontCacheManager.add_kerning(&start_x, &start_y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);

			if(glyph->data_type == agg::glyph_data_outline)
			{
				agg::trans_affine mtx;
				mtx *= agg::trans_affine_translation(-start_x, -start_y);
				mtx *= agg::trans_affine_rotation(dbRot);
				mtx *= agg::trans_affine_translation(tx, ty);
				agg::path_storage glyphps;
				glyphps.concat_path(Curve);
				agg::conv_transform<agg::path_storage> Trans(glyphps,mtx);
				//m_path.remove_all();
				//m_path.concat_path(Trans, 0);
				//drawPath();
				psFont.concat_path(Trans, 0);
			}

			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	addPath(psFont);
	drawPath();
	//restore path storage
	m_path = tmpPath;
	delete []px;
	delete []py;
}

//------------------------------------------------------------------------
double CGisGraphics::textLength(const unsigned short* str)
{
	double start_x = 0.0;
	double start_y = 0.0;
	double x = 0.0;
	double y = 0.0;
	const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
	int i;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(i) m_fontCacheManager.add_kerning(&x, &y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);
			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	return sqrt(start_x*start_x + start_y*start_y);
}

//added by Thai Huy - 03 Mar 2008
//------------------------------------------------------------------------
double CGisGraphics::textLength(const char* str)
{
	double start_x = 0.0;
	double start_y = 0.0;
	double x = 0.0;
	double y = 0.0;
	const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
	int i;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(i) m_fontCacheManager.add_kerning(&x, &y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);
			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	return sqrt(start_x*start_x + start_y*start_y);
}

//added by Thai Huy 28th May 2007
void CGisGraphics::gettextMBR(const unsigned short* str, double startx, double starty, double &x1, double &y1, double &x2, double &y2)
{
	/*double start_x = startx;
	double start_y = starty;
	
	double tx, ty;	
	double maxX, maxY, minX,minY;
	maxX = maxY = -9999999.0;
	minX = minY = DBL_MAX;
	
	const agg::glyph_cache* glyph;
	agg::trans_single_path tcurve;
	tcurve.add_path(m_pathTransform);
	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>             conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>                      conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path> conv_font_trans_type;
	conv_font_curve_type fcurves(m_fontCacheManager.path_adaptor());
	
	conv_font_segm_type  fsegm(fcurves);
	conv_font_trans_type ftrans(fsegm, tcurve);

	int i;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			tx = start_x;
			ty = start_y;
			tcurve.transform(&tx, &ty);
			if(tx < minX)
				minX = tx;
			if(tx > maxX)
				maxX = tx;
			if(ty < minY)
				minY = ty;
			if(ty > maxY)
				maxY = ty;

			if(i) m_fontCacheManager.add_kerning(&start_x, &start_y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);
			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	
	tx = start_x - fontHeight();
	ty = start_y;// - fontHeight() * 4;
	
	tcurve.transform(&tx, &ty);
	if(tx < minX)
		minX = tx;
	if(tx > maxX)
		maxX = tx;
	if(ty < minY)
		minY = ty;
	if(ty > maxY)
		maxY = ty;

	x1 = minX - fontHeight() * 1.5;
 	y1 = minY - fontHeight() / 2;
	x2 = maxX + fontHeight() * 2;
	y2 = maxY  + fontHeight()/ 2;
	
	if(abs(y2 - y1) < fontHeight() * 2)
	{
		
		y1 = y1 - fontHeight() * 2;
		y2 = y2 + fontHeight() / 2 ;
	}
	if(abs(x2 - x1) < fontHeight() / 2)
	{
		x1 = x1 - fontHeight();
		x2 = x2 + fontHeight() / 2;
	}*/
	agg::path_storage pathGlyph;
	glyphToPath(startx, starty, str, pathGlyph);
	agg::bounding_rect_single(pathGlyph, 0, &x1, &y1, &x2, &y2);

}

void CGisGraphics::gettextMBREx(int nLine, const unsigned short* str, double startx, double starty, double &x1, double &y1, double &x2, double &y2)
{
	agg::path_storage tmpPath;
	tmpPath = m_path;
	
	m_path.rewind(0);
	double px1, py1, px2, py2;
	m_path.vertex(0, &px1, &py1);
	m_path.vertex(m_path.total_vertices()-1, &px2, &py2);
	double xxx, yyy;
	double dbSpace = nLine * m_fontHeight;
	agg::calc_orthogonal(-dbSpace, px1, py1, px2, py2, &xxx, &yyy);
	resetPath();
	moveTo(px1+xxx, py1+yyy);
	lineTo(px2+xxx, py2+yyy);
	agg::path_storage pathGlyph;
	glyphToPath(startx, starty, str, pathGlyph);
	agg::bounding_rect_single(pathGlyph, 0, &x1, &y1, &x2, &y2);
	m_path = tmpPath;

}
//------------------------------------------------------------------------
void CGisGraphics::glyphToPath(double x, double y, const unsigned short* str, Path &ps)
{
   double dx = 0.0;
   double dy = 0.0;

   /*switch(m_textAlignX)
   {
	   case AlignCenter:  dx = -textWidth(str) * 0.5; break;
	   case AlignRight:   dx = -textWidth(str);       break;
	   default: break;
   }
	*/

   double asc = fontHeight();
   const agg::glyph_cache* glyph = m_fontCacheManager.glyph('H');
   if(glyph)
   {
	   asc = glyph->bounds.y2 - glyph->bounds.y1;
   }

   if(m_fontCacheType == RasterFontCache)
   {
	   asc = screenToWorld(asc);
   }

   switch(m_textAlignY)
   {
	   case AlignCenter:  dy = -asc * 0.5; break;
	   case AlignTop:     dy = -asc;       break;
	   default: break;
   }

   if(m_fontEngine.flip_y()) dy = -dy;

	double start_x = x + dx;
	double start_y = y + dy;

/*
	agg::trans_single_path SinglePath;
	SinglePath.add_path(m_pathTransform);

	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>				conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>							conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path>	conv_font_trans_type;

	conv_font_curve_type		Curve(m_fontCacheManager.path_adaptor());
	conv_font_segm_type			Segment(Curve);
	conv_font_trans_type		Trans(Segment, SinglePath); 
*/
	typedef agg::conv_bspline<PathTransform> conv_bspline_trans_type;
	typedef agg::conv_bspline<agg::path_storage> conv_bspline_type;
	//conv_bspline_type bspline(m_path);
	conv_bspline_trans_type bspline(m_pathTransform);
	
	bspline.interpolation_step(0.1);
	
	agg::trans_single_path SinglePath;

	SinglePath.add_path(m_pathTransform);
	SinglePath.preserve_x_scale(true);
	
	typedef agg::conv_curve<FontCacheManager::path_adaptor_type>				conv_font_curve_type;
	typedef agg::conv_segmentator<conv_font_curve_type>							conv_font_segm_type;
	typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path>	conv_font_trans_type;
	
	conv_font_curve_type		Curve(m_fontCacheManager.path_adaptor());
	conv_font_segm_type			Segment(Curve);

	if(m_fontCacheType == RasterFontCache)
	{
		worldToScreen(start_x, start_y);
	}

	agg::path_storage tmpPs = m_path;
	tmpPs.rewind(0);
	int numpoints = 0;
	int nvertices = tmpPs.total_vertices();
	double *px = new double[nvertices];
	double *py = new double[nvertices];
	while (tmpPs.vertex(&dx, &dy) != agg::path_cmd_stop)
	{
		px[numpoints] = dx;
		py[numpoints] = dy;
		numpoints++;
	}
	int ncurnode = 0;
	int i;
	for (i = 0; str[i]; i++)
	{
		glyph = m_fontCacheManager.glyph(str[i]);
		if(glyph)
		{
			if(start_x > SinglePath.total_length()) break;
			double tx = start_x;
			double ty = start_y;
			SinglePath.transform(&tx, &ty);
			double d = start_x;
			int jn = 0;
			double D = agg::calc_distance(px[0], py[0], px[1], py[1]);
			while( D < d + 1.0  && jn < nvertices - 1 && nvertices > 2)
			{
				jn++;
				D += agg::calc_distance(px[jn], py[jn], px[jn+1], py[jn+1]);
			}
			ncurnode = jn;
			double dbRot;
			dbRot = atan2(py[ncurnode + 1] - py[ncurnode], px[ncurnode + 1] - px[ncurnode]);

			m_fontCacheManager.add_kerning(&start_x, &start_y);
			m_fontCacheManager.init_embedded_adaptors(glyph, start_x, start_y);

			if(glyph->data_type == agg::glyph_data_outline)
			{
				agg::trans_affine mtx;
				mtx *= agg::trans_affine_translation(-start_x, -start_y);
				mtx *= agg::trans_affine_rotation(dbRot);
				mtx *= agg::trans_affine_translation(tx, ty);
				agg::path_storage glyphps;
				glyphps.concat_path(Curve);
				agg::conv_transform<agg::path_storage> Trans(glyphps,mtx);
				ps.concat_path(Trans, 0);
			}

			start_x += glyph->advance_x;
			start_y += glyph->advance_y;
		}
	}
	delete []px;
	delete []py;

}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
bool CGisGraphics::testClip(Path ps0, Path ps1)
{
	agg::conv_gpc<agg::path_storage, agg::path_storage> gpc(ps0, ps1); 
	gpc.operation(agg::gpc_and);
	Path ps;
	ps.concat_path(gpc);
	ps.rewind(0);
	return (ps.total_vertices() > 0);
//	return false;
}

void CGisGraphics::getClip(agg::path_storage ps0, agg::path_storage ps1, agg::path_storage &ps/*operation*/)
{
	agg::conv_gpc<agg::path_storage, agg::path_storage> gpc(ps0, ps1); 
	gpc.operation(agg::gpc_and);
	ps.concat_path(gpc);

}

void CGisGraphics::resetPath() { m_path.remove_all(); }

//------------------------------------------------------------------------
void CGisGraphics::moveTo(double x, double y)
{
	m_path.move_to(x, y);
}

//------------------------------------------------------------------------
void CGisGraphics::moveRel(double dx, double dy)
{
	m_path.move_rel(dx, dy);
}

//------------------------------------------------------------------------
void CGisGraphics::lineTo(double x, double y)
{
	m_path.line_to(x, y);
}

//------------------------------------------------------------------------
void CGisGraphics::lineRel(double dx, double dy)
{
	m_path.line_rel(dx, dy);
}

//------------------------------------------------------------------------
void CGisGraphics::horLineTo(double x)
{
	m_path.hline_to(x);
}

//------------------------------------------------------------------------
void CGisGraphics::horLineRel(double dx)
{
	m_path.hline_rel(dx);
}

//------------------------------------------------------------------------
void CGisGraphics::verLineTo(double y)
{
	m_path.vline_to(y);
}

//------------------------------------------------------------------------
void CGisGraphics::verLineRel(double dy)
{
	m_path.vline_rel(dy);
}

//------------------------------------------------------------------------
void CGisGraphics::arcTo(double rx, double ry,
				  double angle,
				  bool largeArcFlag,
				  bool sweepFlag,
				  double x, double y)
{
	m_path.arc_to(rx, ry, angle, largeArcFlag, sweepFlag, x, y);
}

//------------------------------------------------------------------------
void CGisGraphics::arcRel(double rx, double ry,
				   double angle,
				   bool largeArcFlag,
				   bool sweepFlag,
				   double dx, double dy)
{
	m_path.arc_rel(rx, ry, angle, largeArcFlag, sweepFlag, dx, dy);
}

//------------------------------------------------------------------------
void CGisGraphics::quadricCurveTo(double xCtrl, double yCtrl,
						   double xTo,   double yTo)
{
	m_path.curve3(xCtrl, yCtrl, xTo, yTo);
}

//------------------------------------------------------------------------
void CGisGraphics::quadricCurveRel(double dxCtrl, double dyCtrl,
							double dxTo,   double dyTo)
{
	m_path.curve3_rel(dxCtrl, dyCtrl, dxTo, dyTo);
}

//------------------------------------------------------------------------
void CGisGraphics::quadricCurveTo(double xTo, double yTo)
{
	m_path.curve3(xTo, yTo);
}

//------------------------------------------------------------------------
void CGisGraphics::quadricCurveRel(double dxTo, double dyTo)
{
	m_path.curve3_rel(dxTo, dyTo);
}

//------------------------------------------------------------------------
void CGisGraphics::cubicCurveTo(double xCtrl1, double yCtrl1,
						 double xCtrl2, double yCtrl2,
						 double xTo,    double yTo)
{
	m_path.curve4(xCtrl1, yCtrl1, xCtrl2, yCtrl2, xTo, yTo);
}

//------------------------------------------------------------------------
void CGisGraphics::cubicCurveRel(double dxCtrl1, double dyCtrl1,
						  double dxCtrl2, double dyCtrl2,
						  double dxTo,    double dyTo)
{
	m_path.curve4_rel(dxCtrl1, dyCtrl1, dxCtrl2, dyCtrl2, dxTo, dyTo);
}

//------------------------------------------------------------------------
void CGisGraphics::cubicCurveTo(double xCtrl2, double yCtrl2,
						 double xTo,    double yTo)
{
	m_path.curve4(xCtrl2, yCtrl2, xTo, yTo);
}

//------------------------------------------------------------------------
void CGisGraphics::cubicCurveRel(double xCtrl2, double yCtrl2,
						  double xTo,    double yTo)
{
	m_path.curve4_rel(xCtrl2, yCtrl2, xTo, yTo);
}

//------------------------------------------------------------------------
void CGisGraphics::addEllipse(double cx, double cy, double rx, double ry, Direction dir)
{
	agg::bezier_arc arc(cx, cy, rx, ry, 0, (dir == CCW) ? 2*pi() : -2*pi());
	//m_path.add_path(arc, 0, false);
	m_path.concat_path(arc,0); // JME
	m_path.close_polygon();
}

void CGisGraphics::addPath(Path ps)
{
	m_path.concat_path(ps, 0);
}
//------------------------------------------------------------------------
void CGisGraphics::closePolygon()
{
   m_path.close_polygon();
}

//------------------------------------------------------------------------
void CGisGraphics::imageFilter(ImageFilter f)
{
	m_imageFilter = f;
	switch(f)
	{
		case NoFilter:    break;
		case Bilinear:    m_imageFilterLut.calculate(agg::image_filter_bilinear(),    true); break;
		case Hanning:     m_imageFilterLut.calculate(agg::image_filter_hanning(),     true); break;
		case Hermite:     m_imageFilterLut.calculate(agg::image_filter_hermite(),     true); break;
		case Quadric:     m_imageFilterLut.calculate(agg::image_filter_quadric(),     true); break;
		case Bicubic:     m_imageFilterLut.calculate(agg::image_filter_bicubic(),     true); break;
		case Catrom:      m_imageFilterLut.calculate(agg::image_filter_catrom(),      true); break;
		case Spline16:    m_imageFilterLut.calculate(agg::image_filter_spline16(),    true); break;
		case Spline36:    m_imageFilterLut.calculate(agg::image_filter_spline36(),    true); break;
		case Blackman144: m_imageFilterLut.calculate(agg::image_filter_blackman144(), true); break;
	}
}

//------------------------------------------------------------------------
CGisGraphics::ImageFilter CGisGraphics::imageFilter() const
{
	return m_imageFilter;
}

//------------------------------------------------------------------------
void CGisGraphics::imageResample(ImageResample f)
{
	m_imageResample = f;
}

//------------------------------------------------------------------------
CGisGraphics::ImageResample CGisGraphics::imageResample() const
{
	return m_imageResample;
}

//------------------------------------------------------------------------
void CGisGraphics::transformImage(const Image& img,    int imgX1,    int imgY1,    int imgX2,    int imgY2,
											 double dstX1, double dstY1, double dstX2, double dstY2)
{
	resetPath();
	moveTo(dstX1, dstY1);
	lineTo(dstX2, dstY1);
	lineTo(dstX2, dstY2);
	lineTo(dstX1, dstY2);
	closePolygon();
	double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
	renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImage(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2)
{
	resetPath();
	moveTo(dstX1, dstY1);
	lineTo(dstX2, dstY1);
	lineTo(dstX2, dstY2);
	lineTo(dstX1, dstY2);
	closePolygon();
	double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
	renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImage(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2,
						   const double* parallelogram)
{
	resetPath();
	moveTo(parallelogram[0], parallelogram[1]);
	lineTo(parallelogram[2], parallelogram[3]);
	lineTo(parallelogram[4], parallelogram[5]);
	lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2],
		   parallelogram[1] + parallelogram[5] - parallelogram[3]);
	closePolygon();
	renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImage(const Image& img, const double* parallelogram)
{
	resetPath();
	moveTo(parallelogram[0], parallelogram[1]);
	lineTo(parallelogram[2], parallelogram[3]);
	lineTo(parallelogram[4], parallelogram[5]);
	lineTo(parallelogram[0] + parallelogram[4] - parallelogram[2],
		   parallelogram[1] + parallelogram[5] - parallelogram[3]);
	closePolygon();
	renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImagePath(const Image& img,    int imgX1,    int imgY1,    int imgX2,    int imgY2,
												 double dstX1, double dstY1, double dstX2, double dstY2)
{
	double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
	renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImagePath(const Image& img, double dstX1, double dstY1, double dstX2, double dstY2)
{
	double parallelogram[6] = { dstX1, dstY1, dstX2, dstY1, dstX2, dstY2 };
	renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImagePath(const Image& img, int imgX1, int imgY1, int imgX2, int imgY2,
							   const double* parallelogram)
{
	renderImage(img, imgX1, imgY1, imgX2, imgY2, parallelogram);
}

//------------------------------------------------------------------------
void CGisGraphics::transformImagePath(const Image& img, const double* parallelogram)
{
	renderImage(img, 0, 0, img.renBuf.width(), img.renBuf.height(), parallelogram);
}

//[added by Thai Huy 2rd May 2007
//------------------------------------------------------------------------
void CGisGraphics::fillPatternPath(const Image& img, unsigned offx, unsigned offy)
{
	m_rasterizer.reset();
	m_rasterizer.add_path(m_pathTransform);
	renderFillPattern(img, offx, offy);

}
//added by Thai Huy 2rd May 2007
//------------------------------------------------------------------------
void CGisGraphics::linePatternPath(const Image& img, double scalex)
{
	m_rasterizer.reset();
	renderLinePattern(img, scalex);
}

//------------- testing -------------------------------------------------
//void CGisGraphics::drawPathNoClip(DrawPathFlag flag)
void CGisGraphics::drawPath(DrawPathFlag flag)
{
   m_rasterizer.reset();
	switch(flag)
	{
	case FillOnly:
		if (m_fillColor.a)
		{
			m_rasterizer.add_path(m_pathTransform);
			render(true);
		}
		break;

	case StrokeOnly:
		if (m_lineColor.a && m_lineWidth > 0.0)
		{
			switch(m_penStyle)
			{
				case AggPsSolid:
					{
						m_rasterizer.add_path(m_strokeTransform);
					}
					
					break;
				case AggPsDash: // --------------------
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDot: // --o--o--o--o
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDashDot: // --o--o--o--o
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				
				case AggPsDot: // o o o o o o o 
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				/*case AggPsDot2: // o o o o o o o 
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, 3);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;*/
				case AggPsDashDotDot: // --- o -- o --- o -- o ---
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;

				case AggPsDashDotDashDot: // --- o -- o --- o -- o ---
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN * 2, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				
				case AggPsDashTriDash:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN * 4, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;

			}
			render(false);
		}
		break;

	case FillAndStroke:
		if (m_fillColor.a)
		{
			m_rasterizer.add_path(m_pathTransform);
			render(true);
		}

		if (m_lineColor.a && m_lineWidth > 0.0)
		{
		   switch(m_penStyle)
			{
				case AggPsSolid:
					{
						m_rasterizer.add_path(m_strokeTransform);
					}
					break;
				case AggPsDash:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDot:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDot:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
			}
			render(false);
		}
		break;

	case FillWithLineColor:
		if (m_lineColor.a)
		{
			m_rasterizer.add_path(m_pathTransform);
			render(true);
		}
		break;
	}
}
//------------------------------------------------------------------------

//void CGisGraphics::drawPath(DrawPathFlag flag)
void CGisGraphics::drawPathNoClip(DrawPathFlag flag)
{
   m_rasterizer.reset();
	switch(flag)
	{
	case FillOnly:
		if (m_fillColor.a)
		{
			PolygonClippTransform Clipped(m_pathTransform);
			Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
			m_rasterizer.add_path(Clipped);
			render(true);
		}
		break;

	case StrokeOnly:
		if (m_lineColor.a && m_lineWidth > 0.0)
		{
			switch(m_penStyle)
			{
				case AggPsSolid:
					{
						m_convStroke.width(0);
						StrokeClippTransform Clipped(m_strokeTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						agg::conv_stroke<StrokeClippTransform> Stroke(Clipped);
						Stroke.width(m_lineWidth);
						m_rasterizer.add_path(Stroke);
						
						/*
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						agg::conv_stroke<ClippTransform> Stroke(Clipped);
						Stroke.width(0);
						//m_rasterizer.add_path(Stroke);
						m_rasterizer.add_path(m_strokeTransform);
						*/
					}
					
					break;
				case AggPsDash: // --------------------
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDot: // --o--o--o--o
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDashDot: // --o--o--o--o
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				
				case AggPsDot: // o o o o o o o 
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				/*case AggPsDot2: // o o o o o o o 
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, 3);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;*/
				case AggPsDashDotDot: // --- o -- o --- o -- o ---
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;

				case AggPsDashDotDashDot: // --- o -- o --- o -- o ---
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN * 2, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				
				case AggPsDashTriDash:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN * 4, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;

			}
			render(false);
		}
		break;

	case FillAndStroke:
		if (m_fillColor.a)
		{
			PolygonClippTransform Clipped(m_pathTransform);
			Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
			m_rasterizer.add_path(Clipped);
			//m_rasterizer.add_path(m_pathTransform);
			render(true);
		}
		m_rasterizer.reset();
		if (m_lineColor.a && m_lineWidth > 0.0)
		{
		   switch(m_penStyle)
			{
				case AggPsSolid:
					{
						m_convStroke.width(0);
						StrokeClippTransform Clipped(m_strokeTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						agg::conv_stroke<StrokeClippTransform> Stroke(Clipped);
						Stroke.width(m_lineWidth);
						m_convStroke.width(m_lineWidth);
						m_rasterizer.add_path(Clipped);
						//m_convStroke.width(m_lineWidth);
						//agg::conv_clip_polyline<ConvStroke> Clipped(m_convStroke);
						//Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						//m_rasterizer.add_path(Clipped);
						//m_convStroke.width(m_lineWidth);
						//m_rasterizer.add_path(m_strokeTransform);
					}
					break;
				case AggPsDash:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDashDot:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DASH_LEN, GAP_LEN);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
				case AggPsDot:
					{
						ClippTransform Clipped(m_pathTransform);
						Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
						DashTransform Dash(Clipped);
						Dash.add_dash(DOT_LEN, GAP_LEN);
						StrokeDashTransform StrokeDash(Dash);
						StrokeDash.width(m_lineWidth);
						m_rasterizer.add_path(StrokeDash);
					}
					break;
			}
			render(false);
		}
		break;

	case FillWithLineColor:
		if (m_lineColor.a)
		{
			PolygonClippTransform Clipped(m_pathTransform);
			Clipped.clip_box(m_clipBox.x1, m_clipBox.y1, m_clipBox.x2, m_clipBox.y2);
			m_rasterizer.add_path(Clipped);
			render(true);
		}
		break;
	}
}

//editted by Thai Huy on 21st May 2007
//------------------------------------------------------------------------
void CGisGraphics::drawArrowPath(double a1, double a2, double a3, double a4)
{
	agg::arrowhead	ahArrow;
	ahArrow.head(a1, a2, a3, a4);
	agg::conv_stroke<agg::path_storage, agg::vcgen_markers_term> stroke(m_path);
	//agg::conv_marker<StrokeTransform, agg::arrowhead> arrow(m_strokeTransform, ahArrow);
	agg::conv_marker<agg::vcgen_markers_term, agg::arrowhead> arrow(stroke.markers(), ahArrow);
	m_rasterizer.add_path(stroke);
	m_rasterizer.add_path(arrow);
	render(false);
}

//editted by Thai Huy on 19th May 2007
//------------------------------------------------------------------------
double CGisGraphics::pathLength()
{
	agg::trans_single_path sp;
	sp.add_path(m_path);
	return sp.total_length();
}

//------------------------------------------------------------------------
class PatternImageSrc
{
public:
	PatternImageSrc(agg::rendering_buffer& rb) : 
		m_rb(&rb), m_pf(*m_rb) {}

	unsigned width()  const { return m_pf.width();  }
	unsigned height() const { return m_pf.height(); }
	agg::rgba8 pixel(int x, int y) const
	{
		agg::rgba8 c = m_pf.pixel(x, y);
		c.a = brightness_to_alpha[c.r + c.g + c.b];
		return c;
	}
public:
	agg::rendering_buffer* m_rb;
	CGisGraphics::PixFormat m_pf;
};

//------------------------------------------------------------------------
class Agg2DRenderer
{

public:
	//added by Thai Huy 2rd May 2007
	//--------------------------------------------------------------------
	template<class BaseRenderer, class SolidRenderer>
		void static renderLinePattern(CGisGraphics& gr, const CGisGraphics::Image& img, double scalex, BaseRenderer& renBase, SolidRenderer& renSolid)
	{
		typedef agg::line_image_pattern<agg::pattern_filter_bilinear_rgba8> pattern_type;
		typedef agg::renderer_base<CGisGraphics::PixFormat> base_ren_type;
		typedef agg::renderer_outline_image<base_ren_type,pattern_type> renderer_vector_type;
		typedef agg::rasterizer_outline_aa<renderer_vector_type, agg::line_coord_sat> rasterizer_img_type;
		
		agg::pattern_filter_bilinear_rgba8 fltr;
		pattern_type patternline2(fltr);
		CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
		PatternImageSrc				patternImgSrc(imgc.renBuf);
		patternline2.create(patternImgSrc);
		//CGisGraphics::PixFormat mpf(imgc.renBuf);
		patternline2.create(patternImgSrc);
		renderer_vector_type	ren_img(renBase, patternline2);
		rasterizer_img_type		ras_img(ren_img);
		ren_img.scale_x(scalex);
		CGisGraphics::ClippTransform Clipped(gr.m_pathTransform);
		Clipped.clip_box(gr.m_clipBox.x1, gr.m_clipBox.y1, gr.m_clipBox.x2, gr.m_clipBox.y2);
		ras_img.add_path(Clipped);
		agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, renSolid);

	}
	//added by Thai Huy 2rd May 2007
	//--------------------------------------------------------------------
	template<class BaseRenderer>
	void static renderFillPattern(CGisGraphics& gr, CGisGraphics::WrapMode wrMode, const CGisGraphics::Image& img, BaseRenderer& renBase, unsigned offx, unsigned offy)
	{
		typedef agg::wrap_mode_repeat WrapXRepeat;
		typedef agg::wrap_mode_repeat WrapYRepeat;

		typedef agg::wrap_mode_repeat_pow2 WrapXRepeatPow2;
		typedef agg::wrap_mode_repeat_pow2 WrapYRepeatPow2;

		typedef agg::wrap_mode_repeat_auto_pow2 WrapXRepeatAutoPow2;
		typedef agg::wrap_mode_repeat_auto_pow2 WrapYRepeatAutoPow2;

		typedef agg::wrap_mode_reflect WrapXReflect;
		typedef agg::wrap_mode_reflect WrapYReflect;

		typedef agg::wrap_mode_reflect_pow2 WrapXReflectPow2;
		typedef agg::wrap_mode_reflect_pow2 WrapYReflectPow2;

		typedef agg::wrap_mode_reflect_auto_pow2 WrapXReflectAutoPow2;
		typedef agg::wrap_mode_reflect_auto_pow2 WrapYReflectAutoPow2;


		switch(wrMode)
		{
		case CGisGraphics::WrapRepeatPow2:
			{
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXRepeatPow2, WrapYRepeatPow2> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);
				break;
			}
		case CGisGraphics::WrapRepeatAutoPow2:
			{
				typedef agg::wrap_mode_repeat_auto_pow2 wrap_x_type;
				typedef agg::wrap_mode_repeat_auto_pow2 wrap_y_type;
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXRepeatAutoPow2, WrapYRepeatAutoPow2> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);

				break;
			}
		case CGisGraphics::WrapReflect:
			{
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXReflect, WrapYReflect> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);

				break;
			}
		case CGisGraphics::WrapReflectPow2:
			{
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXReflectPow2, WrapYReflectPow2> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);

				break;
			}
		case CGisGraphics::WrapReflectAutoPow2:
			{
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXReflectAutoPow2, WrapYReflectAutoPow2> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);

				break;
			}
		default:
			{
				typedef agg::image_accessor_wrap<CGisGraphics::PixFormat, 
									WrapXRepeat, WrapYRepeat> img_source_type;

				typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
				agg::span_allocator<CGisGraphics::ColorType> sa;
				CGisGraphics::Image& imgc =		const_cast<CGisGraphics::Image&>(img);
				
				CGisGraphics::PixFormat			img_pixf(imgc.renBuf);
				img_source_type				img_src(img_pixf);
				span_gen_type				sg(img_src, offx, offy);
				agg::render_scanlines_aa(gr.m_rasterizer, gr.m_scanline, renBase , sa, sg);

			}
		}

	}
	
	//--------------------------------------------------------------------
	template<class BaseRenderer, class SolidRenderer>
	void static render(CGisGraphics& gr, BaseRenderer& renBase, SolidRenderer& renSolid, bool fillColor)
	{
		// JME
		typedef agg::span_allocator<agg::rgba8> span_allocator_type;
		//- typedef agg::renderer_scanline_aa<BaseRenderer, CGisGraphics::LinearGradientSpan> RendererLinearGradient;
		typedef agg::renderer_scanline_aa<BaseRenderer,
										span_allocator_type,
										CGisGraphics::LinearGradientSpan> RendererLinearGradient;
		//- typedef agg::renderer_scanline_aa<BaseRenderer, CGisGraphics::RadialGradientSpan> RendererRadialGradient;
		typedef agg::renderer_scanline_aa<BaseRenderer,
										span_allocator_type,
										CGisGraphics::RadialGradientSpan> RendererRadialGradient;

		if ((fillColor && gr.m_fillGradientFlag == CGisGraphics::Linear) ||
		   (!fillColor && gr.m_lineGradientFlag == CGisGraphics::Linear))
		{
			if (fillColor)
			{
				CGisGraphics::LinearGradientSpan span(/*gr.m_allocator, */
											   gr.m_fillGradientInterpolator,
											   gr.m_linearGradientFunction,
											   gr.m_fillGradient,
											   gr.m_fillGradientD1,
											   gr.m_fillGradientD2);
				//-RendererLinearGradient ren(renBase,span);
				RendererLinearGradient ren(renBase,gr.m_allocator,span);
				agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
			}
			else
			{
				CGisGraphics::LinearGradientSpan span(/*gr.m_allocator,*/
											   gr.m_lineGradientInterpolator,
											   gr.m_linearGradientFunction,
											   gr.m_lineGradient,
											   gr.m_lineGradientD1,
											   gr.m_lineGradientD2);
				//- RendererLinearGradient ren(renBase, span);
				RendererLinearGradient ren(renBase,gr.m_allocator,span);
				agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
			}
		}
		else
		{
			if ((fillColor && gr.m_fillGradientFlag == CGisGraphics::Radial) ||
			   (!fillColor && gr.m_lineGradientFlag == CGisGraphics::Radial))
			{
				if (fillColor)
				{
					CGisGraphics::RadialGradientSpan span(/*gr.m_allocator, */
												   gr.m_fillGradientInterpolator,
												   gr.m_radialGradientFunction,
												   gr.m_fillGradient,
												   gr.m_fillGradientD1,
												   gr.m_fillGradientD2);
					//-RendererRadialGradient ren(renBase, span);
					RendererRadialGradient ren(renBase,gr.m_allocator,span);
					agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
				}
				else
				{
					CGisGraphics::RadialGradientSpan span(/*gr.m_allocator,*/
												   gr.m_lineGradientInterpolator,
												   gr.m_radialGradientFunction,
												   gr.m_lineGradient,
												   gr.m_lineGradientD1,
												   gr.m_lineGradientD2);
					//-RendererRadialGradient ren(renBase, span);
					RendererRadialGradient ren(renBase,gr.m_allocator,span);
					agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ren);
				}
			}
			else
			{
				renSolid.color(fillColor ? gr.m_fillColor : gr.m_lineColor);
				agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, renSolid);
			}
		}
	}

	//--------------------------------------------------------------------
	class SpanConvImageBlend
	{
	public:
		SpanConvImageBlend(CGisGraphics::BlendMode m, CGisGraphics::Color c) :
			m_mode(m), m_color(c)
		{}

		void convert(CGisGraphics::Color* span, int x, int y, unsigned len) const
		{
			unsigned l2;
			CGisGraphics::Color* s2;
			if(m_mode != CGisGraphics::BlendDst)
			{
				l2 = len;
				s2 = span;
				typedef agg::comp_op_adaptor_clip_to_dst_rgba_pre<CGisGraphics::Color, agg::order_rgba> OpType;
				do
				{
					OpType::blend_pix(m_mode,
									  (CGisGraphics::Color::value_type*)s2,
									  m_color.r,
									  m_color.g,
									  m_color.b,
									  CGisGraphics::Color::base_mask,
									  agg::cover_full);
					++s2;
				}
				while(--l2);
			}
			if(m_color.a < CGisGraphics::Color::base_mask)
			{
				l2 = len;
				s2 = span;
				unsigned a = m_color.a;
				do
				{
					s2->r = (s2->r * a) >> CGisGraphics::Color::base_shift;
					s2->g = (s2->g * a) >> CGisGraphics::Color::base_shift;
					s2->b = (s2->b * a) >> CGisGraphics::Color::base_shift;
					s2->a = (s2->a * a) >> CGisGraphics::Color::base_shift;
					++s2;
				}
				while(--l2);
			}
		}

	private:
		CGisGraphics::BlendMode m_mode;
		CGisGraphics::Color     m_color;
	};

	//--------------------------------------------------------------------
	template<class BaseRenderer, class SolidRenderer, class Rasterizer, class Scanline>
	void static render(CGisGraphics& gr, BaseRenderer& renBase, SolidRenderer& renSolid, Rasterizer& ras, Scanline& sl)
	{
		// JME
		typedef agg::span_allocator<agg::rgba8> span_allocator_type;
		typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,CGisGraphics::LinearGradientSpan> RendererLinearGradient;
		typedef agg::renderer_scanline_aa<BaseRenderer,span_allocator_type,CGisGraphics::RadialGradientSpan> RendererRadialGradient;

		if(gr.m_fillGradientFlag == CGisGraphics::Linear)
		{
			CGisGraphics::LinearGradientSpan span(
										   gr.m_fillGradientInterpolator,
										   gr.m_linearGradientFunction,
										   gr.m_fillGradient,
										   gr.m_fillGradientD1,
										   gr.m_fillGradientD2);
			RendererLinearGradient ren(renBase,gr.m_allocator,span);
			agg::render_scanlines(ras, sl, ren);
		}
		else
		{
			if(gr.m_fillGradientFlag == CGisGraphics::Radial)
			{
				CGisGraphics::RadialGradientSpan span(
											   gr.m_fillGradientInterpolator,
											   gr.m_radialGradientFunction,
											   gr.m_fillGradient,
											   gr.m_fillGradientD1,
											   gr.m_fillGradientD2);
				RendererRadialGradient ren(renBase,gr.m_allocator,span);
				agg::render_scanlines(ras, sl, ren);
			}
			else
			{
				renSolid.color(gr.m_fillColor);
				agg::render_scanlines(ras, sl, renSolid);
			}
		}
	}

	//--------------------------------------------------------------------
	//! JME - this is where the bulk of the changes have taken place.
	template<class BaseRenderer, class Interpolator>
	static void renderImage(CGisGraphics& gr, const CGisGraphics::Image& img,
							BaseRenderer& renBase, Interpolator& interpolator)
	{
		//! JME - have not quite figured which part of this is not const-correct
		// hence the cast.
		CGisGraphics::Image& imgc = const_cast<CGisGraphics::Image&>(img);
		CGisGraphics::PixFormat img_pixf(imgc.renBuf);
		PatternImageSrc patt(imgc.renBuf);
		//typedef agg::image_accessor_clone<CGisGraphics::PixFormat> img_source_type;
		//img_source_type source(img_pixf);
		typedef agg::image_accessor_clone<CGisGraphics::PixFormat> img_source_type;
		img_source_type source(patt.m_pf);

		SpanConvImageBlend blend(gr.m_imageBlendMode, gr.m_imageBlendColor);
		if (gr.m_imageFilter == CGisGraphics::NoFilter)
		{

			typedef agg::span_image_filter_rgba_nn<img_source_type,Interpolator> SpanGenType;
			typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
			typedef agg::renderer_scanline_aa<BaseRenderer,CGisGraphics::SpanAllocator,SpanGenType> RendererType;


			SpanGenType sg(source,interpolator);
			SpanConvType sc(sg, blend);
			RendererType ri(renBase,gr.m_allocator,sg);
			agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
			
		}
		else
		{
			bool resample = (gr.m_imageResample == CGisGraphics::ResampleAlways);
			if(gr.m_imageResample == CGisGraphics::ResampleOnZoomOut)
			{
				double sx, sy;
				interpolator.transformer().scaling_abs(&sx,&sy);
				if (sx > 1.125 || sy > 1.125)
				{
					resample = true;
				}
			}

			if (resample)
			{
				typedef agg::span_image_resample_rgba_affine<img_source_type> SpanGenType;
				typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
				typedef agg::renderer_scanline_aa<BaseRenderer,CGisGraphics::SpanAllocator,SpanGenType> RendererType;

				SpanGenType sg(source,interpolator,gr.m_imageFilterLut);
				SpanConvType sc(sg, blend);
				RendererType ri(renBase,gr.m_allocator,sg);
				agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
			}
			else
			{
				// this is the CGisGraphics default
				if (gr.m_imageFilter == CGisGraphics::Bilinear)
				{
					typedef agg::span_image_filter_rgba_bilinear<img_source_type,Interpolator> SpanGenType;
					typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
					typedef agg::renderer_scanline_aa<BaseRenderer,CGisGraphics::SpanAllocator,SpanGenType> RendererType;

					SpanGenType sg(source,interpolator);
					SpanConvType sc(sg, blend);
					RendererType ri(renBase,gr.m_allocator,sg);
					agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
				}
				else
				{
					if(gr.m_imageFilterLut.diameter() == 2)
					{
						typedef agg::span_image_filter_rgba_2x2<img_source_type,Interpolator> SpanGenType;
						typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
						typedef agg::renderer_scanline_aa<BaseRenderer,CGisGraphics::SpanAllocator,SpanGenType> RendererType;

						SpanGenType sg(source,interpolator,gr.m_imageFilterLut);
						SpanConvType sc(sg,blend);
						RendererType ri(renBase,gr.m_allocator,sg);
						agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
					}
					else
					{
						typedef agg::span_image_filter_rgba<img_source_type,Interpolator> SpanGenType;
						typedef agg::span_converter<SpanGenType,SpanConvImageBlend> SpanConvType;
						typedef agg::renderer_scanline_aa<BaseRenderer,CGisGraphics::SpanAllocator,SpanGenType> RendererType;
						SpanGenType sg(source,interpolator,gr.m_imageFilterLut);
						SpanConvType sc(sg, blend);
						RendererType ri(renBase,gr.m_allocator,sg);
						agg::render_scanlines(gr.m_rasterizer, gr.m_scanline, ri);
					}
				}
			}
		}
	}
};



//------------------------------------------------------------------------
void CGisGraphics::render(bool fillColor)
{
	if(m_blendMode == BlendAlpha)
	{
		Agg2DRenderer::render(*this, m_renBase, m_renSolid, fillColor);
	}
	else
	{
		Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, fillColor);
	}
}

//------------------------------------------------------------------------
void CGisGraphics::render(FontRasterizer& ras, FontScanline& sl)
{
	if(m_blendMode == BlendAlpha)
	{
		Agg2DRenderer::render(*this, m_renBase, m_renSolid, ras, sl);
	}
	else
	{
		Agg2DRenderer::render(*this, m_renBaseComp, m_renSolidComp, ras, sl);
	}
}

//------------------------------------------------------------------------
void CGisGraphics::renderImage(const CGisGraphics::Image& img, int x1, int y1, int x2, int y2,
						const double* parl)
{
	agg::trans_affine mtx((double)x1,
						  (double)y1,
						  (double)x2,
						  (double)y2,
						  parl);
	mtx *= m_transform;
	mtx.invert();

	m_rasterizer.reset();
	m_rasterizer.add_path(m_pathTransform);

	typedef agg::span_interpolator_linear<agg::trans_affine> Interpolator;
	Interpolator interpolator(mtx);

	if(m_blendMode == BlendAlpha)
	{
		// JME audit -
		Agg2DRenderer::renderImage(*this,img, m_renBasePre, interpolator);
	}
	else
	{
		Agg2DRenderer::renderImage(*this,img, m_renBaseCompPre, interpolator);
	}
}

//added by Thai Huy 2rd May 2007
//------------------------------------------------------------------------
void CGisGraphics::renderFillPattern(const CGisGraphics::Image& img, unsigned offx, unsigned offy)
{
	Agg2DRenderer::renderFillPattern(*this, m_wrapMode, img, m_renBase, offx, offy);
}

void CGisGraphics::renderLinePattern(const CGisGraphics::Image& img, double scalex)
{
	Agg2DRenderer::renderLinePattern(*this, img, scalex, m_renBase, m_renSolid);
}

CGisGraphics::Image* CGisGraphics::CreateSymbol(LONG lStyle, int r, int g, int b)
{
	CGisGraphics::Image *pImgSymbol = NULL;
	CGisGraphics g2D;
	int nW, nH;
	if(lStyle == 0) // ellipse symbol
	{
		nW = nH = 9;
		pImgSymbol = new CGisGraphics::Image(nW,nH);	
		g2D.attach(*pImgSymbol);
		g2D.clearAll(255,255,255,0);
		g2D.lineWidth(0.5);
		g2D.fillColor(r,g,b);
		g2D.ellipse(nW/2, nH/2, nW/2, nH/2);
	}
	else if(lStyle == 1)
	{
		nW = nH = 9;
		pImgSymbol = new CGisGraphics::Image(nW,nH);	
		g2D.attach(*pImgSymbol);
		g2D.clearAll(255,255,255,0);
		g2D.lineWidth(1);
		g2D.noFill();
		g2D.lineColor(r,g,b);
		
		g2D.moveTo(0,0);
		g2D.lineTo(nW, nH);

		g2D.moveTo(0,nH);
		g2D.lineTo(nW, 0);

		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	return pImgSymbol;

}

CGisGraphics::Image* CGisGraphics::CreateRailwayPattern(LONG lStyle, double dbThick, int r, int g, int b)
{
/*
	CGisGraphics::Image *pImgRailway = NULL;
	CGisGraphics g2D;	
	int nW, nH, nBorder;
	int nR, nG, nB;
	double tx, ty;
	double dbLineWidth;
	nBorder = 2;
	dbLineWidth = 2;
	nR = r;
	nG =g;
	nB = b;
	if(lStyle == 0) // railway ====++++====++++
	{
		nW = 20 * nThick;
		nH = 3 * nThick;
		nBorder *= nThick;
		if(nBorder >= 8)
			nBorder = 8;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		g2D.lineWidth(0.5);
		g2D.fillColor(nR,nG,nB);
		g2D.rectangle(0,nH/2-(nBorder/2),nW/2,nH/2+(nBorder/2));
		g2D.fillColor(255,255,255);
		g2D.rectangle(nW/2,nH/2-(nBorder/2),nW,nH/2+(nBorder/2));
	}
	else if (lStyle == 1) // |--| o |--| o |--| o
	{
		nW = 25 + (nThick+1);
		nH = 4 + (nThick+1);
		if(nBorder >= 8)
			nBorder = 8;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		
		g2D.lineWidth(nThick+0.5);
		g2D.resetPath();
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/2,nH/2);
		
		g2D.moveTo(1,0);
		g2D.lineTo(1,nH);
		
		g2D.moveTo(nW/2,0);
		g2D.lineTo(nW/2,nH);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
		
		g2D.fillColor(0,0,0);
		g2D.ellipse(nW*3/4, nH/2,1,1);
	}
	else if (lStyle == 2) // --|--|--
	{
		nW = 25 + nThick * 3;
		nH = 8 + nThick * 2;
		dbLineWidth = nThick;
		if(dbLineWidth == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(nW/2,0);
		g2D.lineTo(nW/2,nH);
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if(lStyle == 3) // --bb--qq--bb--pp
	{
		nW = 25 + nThick * 2;
		nH = 8 + nThick * 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		nBorder = nH - 4;
		
		tx = nW / 4 - 2;
		ty = nH / 2 - nBorder;
		g2D.moveTo(tx, ty);
		g2D.lineTo(tx, ty + nBorder);
		
		tx = nW / 4 + 2;
		g2D.moveTo(tx, ty);
		g2D.lineTo(tx, ty + nBorder);

		tx = (nW / 4) * 3 - 2;
		ty = nH / 2 + nBorder;
		g2D.moveTo(tx, ty);
		g2D.lineTo(tx, ty - nBorder);
		
		tx = tx + 4;
		g2D.moveTo(tx, ty);
		g2D.lineTo(tx, ty - nBorder);


		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 4) //--|-- --|--
	{
		nW = 25 + nThick * 3;
		nH = 8 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		g2D.moveTo(nThick*2,nH/2);
		g2D.lineTo(nW-nThick*2,nH/2);
		
		g2D.moveTo(nW/2,2);
		g2D.lineTo(nW/2,nH-2);
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 5) // xx o xx o xx o
	{
		nW = 35 + nThick * 3;
		nH = 14 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/4,nH/2);
		g2D.moveTo(0,nH*3/4);
		g2D.lineTo(nW/4,nH/4);
		
		g2D.moveTo(nW*2/4,nH/2);
		g2D.lineTo(nW*3/4,nH/2);
		g2D.moveTo(nW*2/4,nH*3/4);
		g2D.lineTo(nW*3/4,nH/4);

		g2D.drawPath(CGisGraphics::StrokeOnly);
		
		g2D.resetPath();
		g2D.ellipse(nW - nW/8, nH/2 , 1 ,1);
	}
	else if (lStyle == 6)
	{
		nW = 18 + nThick * 3;
		nH = 15 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/2,nH/2);
		g2D.moveTo(0,nH*3/4);
		g2D.lineTo(nW/2,nH/4);
		g2D.drawPath(CGisGraphics::StrokeOnly);
		
		g2D.resetPath();
		g2D.ellipse(3 * nW/4, nH/2 , 1 ,1);
	}
	else if (lStyle == 7)
	{
		nW = 25 + nThick * 3;
		nH = 15 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/4,nH/2);
		
		g2D.moveTo(nW/2,nH/2);
		g2D.lineTo(nW*3/4,nH/2);
		g2D.moveTo(nW/2,nH*3/4);
		g2D.lineTo(nW*3/4,nH/4);
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 8)
	{
		nW = 20 + nThick * 3;
		nH = 15 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(nW/2,nH*3/4);
		g2D.lineTo(nW*3/4,nH/4);

		g2D.moveTo(nW/2,nH/4);
		g2D.lineTo(nW*3/4,nH*3/4);
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 9)
	{
		nW = 8;
		nH = 10;
		dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(1,0);
		g2D.lineTo(1,nH/2);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 10)
	{
		nW = 8;
		nH = 10;
		dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(1,nH);
		g2D.lineTo(1,nH/2);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 11)
	{
		nW = 8;
		nH = 18;
		dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(nW/2,nH/2);
		g2D.lineTo(nW/2 + nH/4,nH*3/4);
		
		g2D.moveTo(nW/2,nH/2);
		g2D.lineTo(nW/2 + nH/4,nH/4);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 12)
	{
		nW = 8;
		nH = 18;
		dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(nW/2,nH/2);
		g2D.lineTo(nW/2 - nH/4,nH*3/4);
		
		g2D.moveTo(nW/2,nH/2);
		g2D.lineTo(nW/2 - nH/4,nH/4);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
	}
	else if (lStyle == 13) // |--| o |--| o |--| o
	{
		nW = 20 + (nThick+1);
		nH = 4 + (nThick+1);
		if(nBorder >= 8)
			nBorder = 8;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		
		g2D.lineWidth(nThick+0.5);
		g2D.resetPath();
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/2,nH/2);
		
		g2D.moveTo(1,1);
		g2D.lineTo(1,nH-1);
		
		g2D.moveTo(nW/2,1);
		g2D.lineTo(nW/2,nH-1);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
		
		g2D.fillColor(0,0,0);
		g2D.ellipse(nW*3/4, nH/2,1,1);
	}
	else if (lStyle == 14) // xx . xx . xx . x
	{
		nW = 35 + nThick * 3;
		nH = 14 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW/3-2,nH/2);
		g2D.moveTo(3,nH*3/4-1);
		g2D.lineTo(nW/4-2,nH/4+1);
		
		g2D.moveTo(nW/3+2,nH/2);
		g2D.lineTo(nW*2/3-3,nH/2);
		g2D.moveTo(nW/3+4,nH*3/4-1);
		g2D.lineTo(nW*2/3-6,nH/4+1);
		
		g2D.drawPath(CGisGraphics::StrokeOnly);
		
		g2D.resetPath();
		g2D.ellipse(nW - nW/6, nH/2 , 1 ,1);
	}
	else if (lStyle == 15) // |-|-|-|
	{
		nW = 6 + nThick * 3;
		nH = 4 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB,255);
		g2D.resetPath();
		
		g2D.moveTo(0,nH/2);
		g2D.lineTo(nW,nH/2);
		
		g2D.moveTo(nW/2,0);
		g2D.lineTo(nW/2,nH);
		g2D.drawPath(CGisGraphics::StrokeOnly);

	}
	else if(lStyle == 16) // |=|=|=|
	{
		nW = 5 + nThick * 3;
		nH = 7 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2.0;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(255,255,255);
		g2D.lineWidth(dbLineWidth);
		g2D.lineColor(nR,nG,nB);
		g2D.resetPath();
		
		g2D.moveTo(0,nBorder+1);
		g2D.lineTo(nW,nBorder+1);
		
		g2D.moveTo(0,nH - nBorder - 1);
		g2D.lineTo(nW,nH - nBorder - 1);
		g2D.drawPath(CGisGraphics::StrokeOnly);
		g2D.resetPath();

		g2D.moveTo(nW/2,0);
		g2D.lineTo(nW/2,nH);
		g2D.drawPath(CGisGraphics::StrokeOnly);

	}
	else if (lStyle == 17)
	{
		nW = 2 + nThick * 3;
		nH = 3 + nThick * 2;
		dbLineWidth = nThick;
		if(nThick == 1)
			dbLineWidth = 2.0;
		pImgRailway = new CGisGraphics::Image(nW,nH);
		g2D.attach(*pImgRailway);
		g2D.clearAll(255,255,255,0);
		
		g2D.fillColor(nR,nG,nB);
		g2D.noLine();
		
		g2D.ellipse(1, nH/2,nThick,nThick);

	}

	return pImgRailway;
*/
	CGisGraphics::Image *pImgRailway = NULL;
	CGisGraphics g2D;	
	double dbW, dbH, dbU;
	int	nBorder;
	int nR, nG, nB;
	double tx, ty;
	double	dbF;

	nR	=	r;
	nG	=	g;
	nB	=	b;
	dbU	=	2;
	dbF	=	(dbThick >= 0.5 && dbThick <= 1) ? dbThick : (dbThick*0.75);

	switch (lStyle)
	{
		case 0: // Railway 
		{
			dbW	=	12*dbU*dbF;
			dbH	=	2*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			g2D.lineWidth(0);
			g2D.fillColor(nR, nG, nB);
			g2D.rectangle(0, dbH, dbW/2, 0);
			g2D.lineWidth(2);
			g2D.fillColor(255, 255, 255);
			g2D.lineColor(nR, nG, nB, 255);
 			g2D.rectangle2(dbW/2, dbH, dbW, 0);
			break;
		}
		case 1: // Country border
		{
			dbF	=	(dbF*0.75 < 1) ? 1 : (dbF*0.75);
			dbW	=	12*dbU*dbF;
			dbH	=	3*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			if (dbThick <= 1)
				dbThick	*=	1.5;
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();

			g2D.moveTo(dbF, dbH/2);
			g2D.lineTo(dbW/2 + dbF, dbH/2);
			
			g2D.moveTo(dbF, 0);
			g2D.lineTo(dbF, dbH);
			
			g2D.moveTo(dbW/2 + dbF, 0);
			g2D.lineTo(dbW/2 + dbF, dbH);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			
			g2D.fillColor(nR, nG, nB, 255);
			g2D.ellipse(dbW*3/4 + dbF, dbH/2, dbF, dbF);
			break;
		}
		case 2: 
		{
			dbW	=	6*dbU*dbF;
			dbH	=	3*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();

			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(dbW/2, 0);
			g2D.lineTo(dbW/2, dbH);
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 3: 
		{
			dbW	=	12*dbU*dbF;
			dbH	=	5*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255,255,255,0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR,nG,nB,255);
			g2D.resetPath();
			g2D.moveTo(0,dbH/2);
			g2D.lineTo(dbW,dbH/2);
			nBorder = (int)(dbH/2);
			
			tx = dbW / 4 - 2;
			ty = dbH / 2 - nBorder;
			g2D.moveTo(tx, ty);
			g2D.lineTo(tx, ty + nBorder);
			
			tx = dbW / 4 + 2;
			g2D.moveTo(tx, ty);
			g2D.lineTo(tx, ty + nBorder);

			tx = (dbW / 4) * 3 - 2;
			ty = dbH / 2 + nBorder;
			g2D.moveTo(tx, ty);
			g2D.lineTo(tx, ty - nBorder);
			
			tx = tx + 4;
			g2D.moveTo(tx, ty);
			g2D.lineTo(tx, ty - nBorder);


			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 4: //--|-- --|--
		{
			dbW	=	8*dbU*dbF;
			dbH	=	3*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)(dbW + 2*dbU*dbF), (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();

			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(dbW/2, 0);
			g2D.lineTo(dbW/2, dbH);
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 5: // Province border conflict
		{
			dbW = 16*dbU*dbF;
			dbH = 6*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)(dbW-dbW*1/8), (int)(dbH));
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.fillColor(255, 255, 255);
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0,dbH/2);
			g2D.lineTo(dbW*2/8,dbH/2);
			g2D.moveTo(dbW*1/16,dbH*4/6);
			g2D.lineTo(dbW*3/16,dbH*2/6);
			
			g2D.moveTo(dbW*3/8,dbH/2);
			g2D.lineTo(dbW*5/8,dbH/2);
			g2D.moveTo(dbW*7/16,dbH*4/6);
			g2D.lineTo(dbW*9/16,dbH*2/6);

			g2D.drawPath(CGisGraphics::StrokeOnly);
			
			g2D.resetPath();
			g2D.fillColor(nR, nG, nB, 255);
			g2D.ellipse(dbW*6/8, dbH/2, dbF, dbF);
			break;
		}
		case 6: // x . x .
		{
			dbW = 16*dbU*dbF;
			dbH = 6*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)(dbW-dbW*4/8), (int)(dbH));
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.fillColor(255, 255, 255);
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0,dbH/2);
			g2D.lineTo(dbW*2/8,dbH/2);
			g2D.moveTo(dbW*1/16,dbH*4/6);
			g2D.lineTo(dbW*3/16,dbH*2/6);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			
			g2D.resetPath();
			g2D.fillColor(nR, nG, nB, 255);
			g2D.ellipse(dbW*3/8, dbH/2, dbF, dbF);
			break;
		}
		case 7: // x x o o x x o o
		{
			dbW = 16*dbU*dbF;
			dbH = 6*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)(dbW), (int)(dbH));
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.fillColor(255, 255, 255);
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0,dbH/2);
			g2D.lineTo(dbW*2/8,dbH/2);
			g2D.moveTo(dbW*1/16,dbH*4/6);
			g2D.lineTo(dbW*3/16,dbH*2/6);
			
			g2D.moveTo(dbW*3/8,dbH/2);
			g2D.lineTo(dbW*5/8,dbH/2);
			g2D.moveTo(dbW*7/16,dbH*4/6);
			g2D.lineTo(dbW*9/16,dbH*2/6);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			
			g2D.resetPath();
			g2D.fillColor(nR, nG, nB, 255);
			g2D.ellipse(dbW*6/8, dbH/2, dbF, dbF);
			g2D.ellipse(dbW*7/8, dbH/2, dbF, dbF);
			break;
		}
		case 8:
		{
			dbW = 16*dbU*dbF;
			dbH = 6*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)(dbW-dbW*2/8), (int)(dbH));
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.fillColor(255, 255, 255);
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW*2/8, dbH/2);
			g2D.moveTo(dbW*1/16, dbH*4/6);
			g2D.lineTo(dbW*3/16, dbH*2/6);
			
			g2D.moveTo(dbW*3/8, dbH/2);
			g2D.lineTo(dbW*5/8, dbH/2);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 9:
		{
			dbW = 8*dbU*dbF;
			dbH = 4*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(dbW/4, dbH);
			g2D.lineTo(dbW*3/4, 0);

			g2D.moveTo(dbW/4, 0);
			g2D.lineTo(dbW*3/4, dbH);
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 10:
		{
			dbW = 4*dbU*dbF;
			dbH = 4*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(1, 0);
			g2D.lineTo(1, dbH/2);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 11:
		{
			dbW = 4*dbU*dbF;
			dbH = 4*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(1, dbH);
			g2D.lineTo(1, dbH/2);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 12:
		{
			dbW = 6*dbU*dbF;
			dbH = 4*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(dbW/2, dbH/2);
			g2D.lineTo(dbW/2 + dbH/2, dbH);
			
			g2D.moveTo(dbW/2, dbH/2);
			g2D.lineTo(dbW/2 + dbH/2, 0);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
		case 13:
		{
			dbW = 6*dbU*dbF;
			dbH = 4*dbU*dbF;
			pImgRailway = new CGisGraphics::Image((int)dbW, (int)dbH);
			g2D.attach(*pImgRailway);
			g2D.clearAll(255, 255, 255, 0);
			
			g2D.lineWidth(dbThick);
			g2D.lineColor(nR, nG, nB, 255);
			g2D.resetPath();
			
			g2D.moveTo(0, dbH/2);
			g2D.lineTo(dbW, dbH/2);
			
			g2D.moveTo(dbW/2, dbH/2);
			g2D.lineTo(dbW/2 - dbH/2, dbH);
			
			g2D.moveTo(dbW/2, dbH/2);
			g2D.lineTo(dbW/2 - dbH/2, 0);
			
			g2D.drawPath(CGisGraphics::StrokeOnly);
			break;
		}
	}

	return pImgRailway;

}

//------------------------------------------------------------------------
struct Agg2DRasterizerGamma
{
	Agg2DRasterizerGamma(double alpha, double gamma) :
		m_alpha(alpha), m_gamma(gamma) {}

	double operator() (double x) const
	{
		return m_alpha(m_gamma(x));
	}
	agg::gamma_multiply m_alpha;
	agg::gamma_power    m_gamma;
};

//------------------------------------------------------------------------
void CGisGraphics::updateRasterizerGamma()
{
	m_rasterizer.gamma(Agg2DRasterizerGamma(m_masterAlpha, m_antiAliasGamma));
}

//------------------------------------------------------------------------
void CGisGraphics::blendImage(CGisGraphics::Image& img,
					   int imgX1, int imgY1, int imgX2, int imgY2,
					   double dstX, double dstY, unsigned alpha)
{
	worldToScreen(dstX, dstY);
	PixFormat pixF(img.renBuf);
	// JME
	//agg::rect r(imgX1, imgY1, imgX2, imgY2);
	Rect r(imgX1, imgY1, imgX2, imgY2);
	if(m_blendMode == BlendAlpha)
	{
		m_renBasePre.blend_from(pixF, &r, int(dstX)-imgX1, int(dstY)-imgY1, alpha);
	}
	else
	{
		m_renBaseCompPre.blend_from(pixF, &r, int(dstX)-imgX1, int(dstY)-imgY1, alpha);
	}
}

//------------------------------------------------------------------------
void CGisGraphics::blendImage(CGisGraphics::Image& img, double dstX, double dstY, unsigned alpha)
{
	worldToScreen(dstX, dstY);
	PixFormat pixF(img.renBuf);
	m_renBasePre.blend_from(pixF, 0, int(dstX), int(dstY), alpha);
	if(m_blendMode == BlendAlpha)
	{
		m_renBasePre.blend_from(pixF, 0, int(dstX), int(dstY), alpha);
	}
	else
	{
		m_renBaseCompPre.blend_from(pixF, 0, int(dstX), int(dstY), alpha);
	}
}

//------------------------------------------------------------------------
void CGisGraphics::copyImage(CGisGraphics::Image& img,
					  int imgX1, int imgY1, int imgX2, int imgY2,
					  double dstX, double dstY)
{
	worldToScreen(dstX, dstY);
	// JME
	//agg::rect r(imgX1, imgY1, imgX2, imgY2);
	Rect r(imgX1, imgY1, imgX2, imgY2);
	m_renBase.copy_from(img.renBuf, &r, int(dstX)-imgX1, int(dstY)-imgY1);
}

//------------------------------------------------------------------------
void CGisGraphics::copyImage(CGisGraphics::Image& img, double dstX, double dstY)
{
	worldToScreen(dstX, dstY);
	m_renBase.copy_from(img.renBuf, 0, int(dstX), int(dstY));
}

//added by Thai Huy
//-------------------------------------------------------------------------
//if zorder < 0 - don't care
//if zorder >= 0 - check the right order & type

bool CGisGraphics::drawShape(CompoundShape &shape, DrawPathFlag flag, int nType, int nZorder, int nAlpha)
{
	m_rasterizer.reset();
	agg::conv_stroke<CompoundShape> strokeshape(shape);
	int nCount = shape.paths();
	bool brt = false;
	int i;

	switch(flag)
	{
	case FillOnly:
		if (m_fillColor.a)
		{
			path_style *pstyle;

			strokeshape.line_cap(agg::round_cap);
			strokeshape.line_join(agg::round_join);
			strokeshape.width(m_lineWidth);
			for(i = 0 ; i < nCount ; i++)
			{
				pstyle = shape.style(i);
				
				if(pstyle->type == nType && pstyle->zorder == nZorder)
				{
					
					if (pstyle->zorder < 0)
					{
						m_lineColor.a = nAlpha;
						m_fillColor.a = nAlpha;
					}
					else
					{
						m_lineColor.a = 255;
						m_fillColor.a = 255;
					}
					
					m_rasterizer.add_path(strokeshape,pstyle->path_id);
					brt = true;
					
				}
			}
			render(true);
		}
		break;

	case StrokeOnly:
		if (m_lineColor.a && m_lineWidth > 0.0)
		{
			path_style *pstyle;
			agg::conv_stroke<agg::conv_stroke<CompoundShape> > s(strokeshape);
			s.width(1.5);
			if(nZorder == 1)// || nZorder == 0)
				strokeshape.line_cap(agg::butt_cap);
			else
				strokeshape.line_cap(agg::round_cap); 
			strokeshape.line_join(agg::round_join);
			strokeshape.width(m_lineWidth);
			
			for(i = 0 ; i < nCount ; i++)
			{
				pstyle = shape.style(i);
				
				if(pstyle->type == nType && pstyle->zorder == nZorder)
				{
					
					if (pstyle->zorder < 0)
					{
						m_lineColor.a = nAlpha;						
					}
					else
					{
						m_lineColor.a = 255;
					}
					
					m_rasterizer.add_path(strokeshape,pstyle->path_id);
					brt = true;
					render(false);
				}
			}
		}
		break;
	case FillWithLineColor:
		if (m_lineColor.a)
		{
			m_rasterizer.add_path(m_pathTransform);
			render(false);
		}
		break;
	case Other:
		{
			if (m_lineColor.a && m_lineWidth > 0.0)
			{
				path_style *pstyle;				
				for(i = 0 ; i < nCount ; i++)
				{
					pstyle = shape.style(i);
					
					if(pstyle->type == nType && pstyle->zorder == nZorder &&
						pstyle->zorder < 0)
					{						
						DashStrokeShape dashSShape(strokeshape);
						StrokeDashSShape strokeDSShape(dashSShape);

						nAlpha = m_lineColor.a;
						m_lineColor.a = 0;
						strokeshape.line_cap(agg::round_cap); 
						strokeshape.line_join(agg::round_join);
						strokeshape.width(m_lineWidth);
						m_rasterizer.add_path(strokeshape,pstyle->path_id);
						agg::render_scanlines_aa_solid(m_rasterizer, m_scanline, m_renBase, m_lineColor);
						
						//m_lineColor.a = 100;
						//lineColor(0, 0, 0, nAlpha);
						//m_lineColor.a = nAlpha;
						m_lineColor.a = nAlpha;
						lineColor(m_lineColor);
						strokeDSShape.width(1.0);
						strokeDSShape.line_cap(agg::round_cap); 
						strokeDSShape.line_join(agg::round_join);
						dashSShape.add_dash(m_dbDash, m_dbGap);
						m_rasterizer.add_path(strokeDSShape, pstyle->path_id);
						agg::render_scanlines_aa_solid(m_rasterizer, m_scanline, m_renBase, m_lineColor);
						brt = true;
						render(false);
					}
				}
			}
		}
		break;
	}
	return brt;
}

void CGisGraphics::SetDashGap(double d, double g)
{
	m_dbDash = d;
	m_dbGap = g;
}
